Route protection
Redirect anonymous navigation while preserving backend authorization as the security boundary.
Route protection waits until the auth state is known, then redirects anonymous users. It controls navigation only. It does not protect Convex data.
Configure defaults
export default defineNuxtConfig({
modules: ['@lupinum/better-convex-nuxt'],
convex: {
auth: {
origin: process.env.SITE_URL ?? 'http://localhost:3000',
redirectTo: '/auth/sign-in',
},
},
})Protect a page
definePageMeta({
convexAuth: true,
})For a page-specific destination:
definePageMeta({
convexAuth: { redirectTo: '/account/login' },
})Only local redirect paths are accepted. Protocol-relative paths, backslashes, control characters, and unsafe decoded paths are rejected. An unsafe page-specific redirectTo falls back to convex.auth.redirectTo; the page stays protected.
Keep signed-in users off guest pages
Mark a sign-in or sign-up page as guest-only:
definePageMeta({
convexAuth: 'guest',
})A signed-out visitor sees the page. A signed-in visitor goes to the validated
redirect query path, or else to convex.auth.guestRedirectTo (default /).
The middleware never redirects to the current page, and it ignores a repeated
redirect parameter.
Preserve the return path
The middleware always appends a validated local redirect query value. After
sign-in, read it with useConvexAuthReturnTo(). It returns the normalized path,
or null when the value is missing, repeated, or unsafe:
const returnTo = useConvexAuthReturnTo()
async function afterSignIn() {
await navigateTo(returnTo.value ?? '/dashboard')
}To validate another value, call normalizeLocalRedirectPath(value). It
accepts any input and returns a safe local path or null. Never navigate to an
external URL from a query parameter.
Public pages
Pages without convexAuth metadata remain public by default. An authenticated application can combine public auth: 'none' content and private controls on the same page without protecting the route.
To protect every page by default, set routes: 'protected':
export default defineNuxtConfig({
convex: {
auth: {
origin: process.env.SITE_URL ?? 'http://localhost:3000',
redirectTo: '/auth/sign-in',
routes: 'protected',
},
},
})Then a page without metadata requires sign-in. Opt a public page out with
definePageMeta({ convexAuth: false }). The sign-in page never redirects to
itself.
Permission checks
Authentication can be resolved in middleware. Product permissions normally require backend data.
Prefer to render the page and query the user's permissions from Convex, unless the navigation itself must be blocked. A permission check in middleware only changes what the user sees. The Convex function must repeat the check.
Caching warning
Do not cache an authenticated SSR page as public HTML. A redirect middleware does not split a shared cache by user.