Skip to content

Commit

Permalink
Merge branch 'main' into main
Browse files Browse the repository at this point in the history
  • Loading branch information
Timbological authored Sep 25, 2023
2 parents e727250 + 92f44bc commit e4949a3
Show file tree
Hide file tree
Showing 8 changed files with 69 additions and 8 deletions.
3 changes: 2 additions & 1 deletion docs/content/3.application-side/4.protecting-pages.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
# Protecting Pages

`nuxt-auth` offers different approaches to protect pages:

1. Global protection: Protects all pages with manual exceptions
2. Local protection: Protects specific pages
3. Custom middleware: Create your own middleware
Expand Down Expand Up @@ -48,6 +49,7 @@ That's it! Every page of your application will now need authentication for the u
### Disabling the global middleware locally

To disable the global middleware on a specific page only, you can use the [`definePageMeta` macro](https://nuxt.com/docs/api/utils/define-page-meta#definepagemeta) to turn `auth` off:

```vue
<!-- file: ~/pages/index.vue -->
<template>
Expand All @@ -61,7 +63,6 @@ definePageMeta({ auth: false })

Note: This only works on `pages/`. It notably does not work inside the `app.vue`.


## Local middleware

To protect specific pages with a middleware, you can use the [`definePageMeta` macro](https://nuxt.com/docs/api/utils/define-page-meta#definepagemeta) to turn `auth` on:
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
# Session Access and Management

## `useAuth` Composable

The `useAuth` composable is your main gateway to accessing and manipulating session-state and data. Here's the main methods you can use:
::code-group
```ts [authjs]
Expand Down Expand Up @@ -132,6 +134,18 @@ This is a configuration option available to dynamically type the `SessionData` t

`nuxt-auth` uses [unjs/knitwork](https://github.com/unjs/knitwork) to generate the correct typescript interface from the type you provide.

## Force refetching the session (`local` provider only)

Calling `getSession` will by default **only** refetch the current session if the token returned by `useAuthState` is defined.
Passing the `{ force: true }` option will always update the current session:

::code-group
```ts [local]
// force update the current session
await getSession({ force: true })
```
::

## Redirects

You can also pass the `callbackUrl` option to both the `signIn`, the `signOut` and the `getSession` methods. This allows you to redirect a user to a certain pages, after they've completed the action. This can be useful when a user attempts to open a page (`/protected`) but has to go through external authentication (e.g., via their google account) first.
Expand Down
14 changes: 14 additions & 0 deletions docs/content/v0.6/3.application-side/4.protecting-pages.md
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,20 @@ export default defineNuxtConfig({

That's it! Every page of your application will now need authentication for the user to visit it.

### Middleware Options

#### `unauthenticatedOnly`

Whether to only allow unauthenticated users to access this page. Authenticated users will be redirected to `/` or the route defined in `navigateAuthenticatedTo`

#### `navigateAuthenticatedTo`

Where to redirect authenticated users if `unauthenticatedOnly` is set to true

#### `navigateUnauthenticatedTo`

Where to redirect unauthenticated users if this page is protected

### Disabling the global middleware locally

To disable the global middleware on a specific page only, you can use the [`definePageMeta` macro](https://nuxt.com/docs/api/utils/define-page-meta#definepagemeta) to turn `auth` off:
Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@sidebase/nuxt-auth",
"version": "0.6.0-beta.5",
"version": "0.6.0-beta.6",
"license": "MIT",
"type": "module",
"exports": {
Expand Down
4 changes: 2 additions & 2 deletions src/runtime/composables/local/useAuth.ts
Original file line number Diff line number Diff line change
Expand Up @@ -72,11 +72,11 @@ const getSession: GetSessionFunc<SessionData | null | void> = async (getSessionO
const { path, method } = config.endpoints.getSession
const { data, loading, lastRefreshedAt, token, rawToken } = useAuthState()

if (!token.value) {
if (!token.value && !getSessionOptions?.force) {
return
}

const headers = new Headers({ [config.token.headerName]: token.value } as HeadersInit)
const headers = new Headers(token.value ? { [config.token.headerName]: token.value } as HeadersInit : undefined)

loading.value = true
try {
Expand Down
27 changes: 25 additions & 2 deletions src/runtime/middleware/auth.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,23 @@ import { navigateToAuthPages, determineCallbackUrl } from '../utils/url'
import { useAuth } from '#imports'

type MiddlewareMeta = boolean | {
unauthenticatedOnly: true,
/** Whether to only allow unauthenticated users to access this page.
*
* Authenticated users will be redirected to `/` or the route defined in `navigateAuthenticatedTo`
*
* @default undefined
*/
unauthenticatedOnly?: boolean,
/** Where to redirect authenticated users if `unauthenticatedOnly` is set to true
*
* @default undefined
*/
navigateAuthenticatedTo?: string,
/** Where to redirect unauthenticated users if this page is protected
*
* @default undefined
*/
navigateUnauthenticatedTo?: string
}

declare module '#app/../pages/runtime/composables' {
Expand All @@ -14,7 +29,13 @@ declare module '#app/../pages/runtime/composables' {
}

export default defineNuxtRouteMiddleware((to) => {
const metaAuth = to.meta.auth
const metaAuth = typeof to.meta.auth === 'object'
? {
unauthenticatedOnly: true,
...to.meta.auth
}
: to.meta.auth

if (metaAuth === false) {
return
}
Expand Down Expand Up @@ -60,6 +81,8 @@ export default defineNuxtRouteMiddleware((to) => {
const signInOptions: Parameters<typeof signIn>[1] = { error: 'SessionRequired', callbackUrl: determineCallbackUrl(authConfig, () => to.path) }
// @ts-ignore This is valid for a backend-type of `authjs`, where sign-in accepts a provider as a first argument
return signIn(undefined, signInOptions) as ReturnType<typeof navigateToAuthPages>
} else if (typeof metaAuth === 'object' && metaAuth.navigateUnauthenticatedTo) {
return navigateTo(metaAuth.navigateUnauthenticatedTo)
} else {
return navigateTo(authConfig.provider.pages.login)
}
Expand Down
5 changes: 5 additions & 0 deletions src/runtime/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -339,6 +339,11 @@ export type GetSessionOptions = Partial<{
required?: boolean
callbackUrl?: string
onUnauthenticated?: () => void
/** Whether to refetch the session even if the token returned by useAuthState is null.
*
* @default false
*/
force?: boolean
}>

// TODO: These types could be nicer and more general, or located withing `useAuth` files and more specific
Expand Down
8 changes: 6 additions & 2 deletions src/runtime/utils/url.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { joinURL } from 'ufo'
import getURL from 'requrl'
import { sendRedirect } from 'h3'
import { useRequestEvent, useNuxtApp } from '#app'
import { useRequestEvent, useNuxtApp, abortNavigation } from '#app'
import { useAuthState, useRuntimeConfig } from '#imports'

export const getRequestURL = (includePath = true) => getURL(useRequestEvent()?.node.req, includePath)
Expand All @@ -24,7 +24,11 @@ export const navigateToAuthPages = (href: string) => {

if (process.server) {
if (nuxtApp.ssrContext && nuxtApp.ssrContext.event) {
return nuxtApp.callHook('app:redirected').then(() => sendRedirect(nuxtApp.ssrContext!.event, href, 302))
return nuxtApp.callHook('app:redirected').then(() => {
sendRedirect(nuxtApp.ssrContext!.event, href, 302)

abortNavigation()
})
}
}

Expand Down

0 comments on commit e4949a3

Please sign in to comment.