Best practice for preserving intended URL when redirecting unauthenticated users in Better Auth

When an unauthenticated user visits a protected page (e.g. /dashboard), my Next.js middleware detects that they are not signed in and redirects them to my sign-in page at /sign-in. A common practice is to preserve the original URL in a query parameter, such as /sign-in?redirect_url=/dashboard, so that after the user successfully authenticates, they can be redirected back to the page they originally tried to visit. What is the best practice to implement this pattern when using Better Auth? Here is the approach I have come up with so far: Middleware:
import { NextRequest, NextResponse } from 'next/server'
import { getSessionCookie } from 'better-auth/cookies'

export async function middleware(request: NextRequest) {
const sessionCookie = getSessionCookie(request)

if (!sessionCookie) {
const redirectUrl = encodeURIComponent(request.nextUrl.pathname + request.nextUrl.search)
const signInUrl = new URL(`/sign-in?redirect_url=${redirectUrl}`, request.url)

return NextResponse.redirect(signInUrl)
}

return NextResponse.next()
}

export const config = {
matcher: ['/dashboard(.*)'],
}
import { NextRequest, NextResponse } from 'next/server'
import { getSessionCookie } from 'better-auth/cookies'

export async function middleware(request: NextRequest) {
const sessionCookie = getSessionCookie(request)

if (!sessionCookie) {
const redirectUrl = encodeURIComponent(request.nextUrl.pathname + request.nextUrl.search)
const signInUrl = new URL(`/sign-in?redirect_url=${redirectUrl}`, request.url)

return NextResponse.redirect(signInUrl)
}

return NextResponse.next()
}

export const config = {
matcher: ['/dashboard(.*)'],
}
Sign-in handling:
const searchParams = new URLSearchParams(window.location.search)
const redirectUrl = searchParams.get('redirect_url') ?? '/dashboard'

const { error } = await authClient.signIn.email(
{
email: values.email,
password: values.password,
callbackURL: redirectUrl,
},
{
onRequest: () => setPending(true),
onResponse: () => setPending(false),
}
)
const searchParams = new URLSearchParams(window.location.search)
const redirectUrl = searchParams.get('redirect_url') ?? '/dashboard'

const { error } = await authClient.signIn.email(
{
email: values.email,
password: values.password,
callbackURL: redirectUrl,
},
{
onRequest: () => setPending(true),
onResponse: () => setPending(false),
}
)
Is this approach correct and safe when using Better Auth? Are there recommended patterns to handle this flow?
1 Reply
FalconiZzare
FalconiZzare4mo ago
I'm using the middleware approach. As suggested in the docs, im just checking the existence of the cookie in middleware and on the layout of each protected page i'm doing the actual session checking by calling the server. Using cookiecache.

Did you find this page helpful?