Skip to content

Commit 1aa5e17

Browse files
authored
fix(#926): correct and clarify Guest Mode (#929)
1 parent 734953f commit 1aa5e17

File tree

2 files changed

+75
-31
lines changed

2 files changed

+75
-31
lines changed

docs/guide/application-side/protecting-pages.md

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -78,10 +78,12 @@ definePageMeta({
7878

7979
#### `unauthenticatedOnly`
8080

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

83-
:::tip
84-
Setting `unauthenticatedOnly: false` is equivalent to setting `auth: false` from the user perspective, but requires some extra middleware steps, so it is a bit less efficient. Therefore it is recommended to use `auth: false` instead.
83+
If you want to let everyone see the page, set `auth: false` instead (see [Local Middleware](#local-middleware)).
84+
85+
:::warning
86+
This option is required from `0.9.4` onwards to prevent ambiguity ([related issue](https://github.com/sidebase/nuxt-auth/issues/926)). Make sure you set it, otherwise [Guest Mode](#guest-mode) will be **enabled** by default — your guests would be able to see the page, but your authenticated users would be redirected away.
8587
:::
8688

8789
#### `navigateAuthenticatedTo`

src/runtime/middleware/auth.ts

Lines changed: 70 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,15 @@
11
import type { navigateToAuthPages } from '../utils/url'
22
import { determineCallbackUrl } from '../utils/url'
3+
import { isProduction } from '../helpers'
34
import { defineNuxtRouteMiddleware, navigateTo, useAuth, useRuntimeConfig } from '#imports'
45

56
type MiddlewareMeta = boolean | {
67
/**
7-
* Whether to only allow unauthenticated users to access this page.
8+
* Whether to allow only unauthenticated users to access this page.
89
*
910
* Authenticated users will be redirected to `/` or the route defined in `navigateAuthenticatedTo`
10-
*
11-
* @default undefined
1211
*/
13-
unauthenticatedOnly?: boolean
12+
unauthenticatedOnly: boolean
1413
/**
1514
* Where to redirect authenticated users if `unauthenticatedOnly` is set to true
1615
*
@@ -38,41 +37,34 @@ declare module 'vue-router' {
3837
}
3938

4039
export default defineNuxtRouteMiddleware((to) => {
41-
const metaAuth = typeof to.meta.auth === 'object'
42-
? {
43-
unauthenticatedOnly: true,
44-
...to.meta.auth
45-
}
46-
: to.meta.auth
47-
48-
if (metaAuth === false) {
40+
// Normalize options. If `undefined` was returned, we need to skip middleware
41+
const options = normalizeUserOptions(to.meta.auth)
42+
if (!options) {
4943
return
5044
}
5145

5246
const authConfig = useRuntimeConfig().public.auth
5347
const { status, signIn } = useAuth()
54-
const isGuestMode = typeof metaAuth === 'object' && metaAuth.unauthenticatedOnly
55-
// Guest mode happy path 1: Unauthenticated user is allowed to view page
48+
49+
// Guest Mode - only unauthenticated users are allowed
50+
const isGuestMode = options.unauthenticatedOnly
51+
const isAuthenticated = status.value === 'authenticated'
5652
if (isGuestMode && status.value === 'unauthenticated') {
53+
// Guest Mode - unauthenticated users can stay on the page
5754
return
5855
}
59-
60-
// Guest mode edge-case: Developer used guest-mode config style but set `unauthenticatedOnly` to `false`
61-
if (typeof metaAuth === 'object' && !metaAuth.unauthenticatedOnly) {
62-
return
56+
else if (isGuestMode && isAuthenticated) {
57+
// Guest Mode - authenticated users should be redirected to another page
58+
return navigateTo(options.navigateAuthenticatedTo)
6359
}
64-
65-
if (status.value === 'authenticated') {
66-
// Guest mode happy path 2: Authenticated user should be directed to another page
67-
if (isGuestMode) {
68-
return navigateTo(metaAuth.navigateAuthenticatedTo ?? '/')
69-
}
60+
else if (isAuthenticated) {
61+
// Authenticated users don't need any further redirects
7062
return
7163
}
7264

7365
// We do not want to block the login page when the local provider is used
74-
if (authConfig.provider?.type === 'local') {
75-
const loginRoute: string | undefined = authConfig.provider?.pages?.login
66+
if (authConfig.provider.type === 'local') {
67+
const loginRoute: string | undefined = authConfig.provider.pages.login
7668
if (loginRoute && loginRoute === to.path) {
7769
return
7870
}
@@ -101,9 +93,13 @@ export default defineNuxtRouteMiddleware((to) => {
10193
// @ts-ignore This is valid for a backend-type of `authjs`, where sign-in accepts a provider as a first argument
10294
return signIn(undefined, signInOptions) as ReturnType<typeof navigateToAuthPages>
10395
}
104-
if (typeof metaAuth === 'object' && metaAuth.navigateUnauthenticatedTo) {
105-
return navigateTo(metaAuth.navigateUnauthenticatedTo)
96+
97+
// Redirect path was provided
98+
if (options.navigateUnauthenticatedTo) {
99+
return navigateTo(options.navigateUnauthenticatedTo)
106100
}
101+
102+
// Default callback URL was provided
107103
if (typeof globalAppMiddleware === 'object' && globalAppMiddleware.addDefaultCallbackUrl) {
108104
let redirectUrl: string = to.fullPath
109105
if (typeof globalAppMiddleware.addDefaultCallbackUrl === 'string') {
@@ -117,5 +113,51 @@ export default defineNuxtRouteMiddleware((to) => {
117113
}
118114
})
119115
}
116+
117+
// Fall back to login page
120118
return navigateTo(authConfig.provider.pages.login)
121119
})
120+
121+
interface MiddlewareOptionsNormalized {
122+
unauthenticatedOnly: boolean
123+
navigateAuthenticatedTo: string
124+
navigateUnauthenticatedTo?: string
125+
}
126+
127+
/**
128+
* @returns `undefined` is returned when passed options are `false`
129+
*/
130+
function normalizeUserOptions(userOptions: MiddlewareMeta | undefined): MiddlewareOptionsNormalized | undefined {
131+
// false - do not use middleware
132+
// true - use defaults
133+
if (typeof userOptions === 'boolean' || userOptions === undefined) {
134+
return userOptions !== false
135+
? {
136+
// Guest Mode off if `auth: true`
137+
unauthenticatedOnly: false,
138+
navigateAuthenticatedTo: '/',
139+
navigateUnauthenticatedTo: undefined
140+
}
141+
: undefined
142+
}
143+
144+
// We check in runtime in case usage error was not caught by TS
145+
if (typeof userOptions === 'object') {
146+
// Guest Mode on to preserve compatibility. A warning is also issued to prevent unwanted behaviour
147+
if (userOptions.unauthenticatedOnly === undefined) {
148+
if (!isProduction) {
149+
console.warn(
150+
'[@sidebase/nuxt-auth] `unauthenticatedOnly` was not provided to `definePageMeta` - defaulting to Guest Mode enabled. '
151+
+ 'Read more at https://auth.sidebase.io/guide/application-side/protecting-pages#middleware-options'
152+
)
153+
}
154+
userOptions.unauthenticatedOnly = true
155+
}
156+
157+
return {
158+
unauthenticatedOnly: userOptions.unauthenticatedOnly,
159+
navigateAuthenticatedTo: userOptions.navigateAuthenticatedTo ?? '/',
160+
navigateUnauthenticatedTo: userOptions.navigateUnauthenticatedTo
161+
}
162+
}
163+
}

0 commit comments

Comments
 (0)