Fix post-login redirect when the session cookie is off-origin
Signing in showed the "Welcome back!" toast but never left /login. The session cookie was host-only on the API subdomain, so the Next middleware guard on the site origin saw no cookie and bounced /dashboard straight back to /login?redirect=/dashboard. - Add AUTH_COOKIE_DOMAIN, wiring Better Auth's crossSubDomainCookies so the cookie also reaches the site origin. Unset in dev, where localhost is single-host and must stay host-only. - Navigate after authentication with a full page load, via a shared authRedirect helper: only a top-level request carries the httpOnly cookie. Used by the login, register, magic-link and Google flows. - Show "Redirecting..." on the login and register pages and keep the submit button disabled until the browser replaces the page, instead of re-enabling it mid-navigation. - Guard against a redirect loop with a sessionStorage marker. A React ref cannot do this: the full page load resets component state. If the destination bounces back, explain it rather than navigating again. - Middleware: accept any *.session_token cookie so a cookiePrefix change cannot lock everyone out, and preserve the destination's query string. - Trust any loopback port in dev, so reaching the dev server through a forwarded port does not fail Better Auth's CSRF origin check. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 4.6
parent
733d2459df
commit
dafa3711f8
@@ -13,16 +13,25 @@ const SESSION_COOKIES = [
|
||||
'spanglish.session_token', // development
|
||||
];
|
||||
|
||||
// Matched as a fallback so a change to Better Auth's `advanced.cookiePrefix` cannot
|
||||
// silently lock every user out of these routes.
|
||||
const SESSION_COOKIE_SUFFIX = '.session_token';
|
||||
|
||||
function hasSessionCookie(request: NextRequest): boolean {
|
||||
if (SESSION_COOKIES.some((name) => !!request.cookies.get(name)?.value)) return true;
|
||||
return request.cookies
|
||||
.getAll()
|
||||
.some((cookie) => cookie.name.endsWith(SESSION_COOKIE_SUFFIX) && !!cookie.value);
|
||||
}
|
||||
|
||||
export function middleware(request: NextRequest) {
|
||||
const { pathname } = request.nextUrl;
|
||||
const { pathname, search } = request.nextUrl;
|
||||
|
||||
if (pathname.startsWith('/admin') || pathname.startsWith('/dashboard')) {
|
||||
const hasSessionCookie = SESSION_COOKIES.some(
|
||||
(name) => !!request.cookies.get(name)?.value
|
||||
);
|
||||
if (!hasSessionCookie) {
|
||||
if (!hasSessionCookie(request)) {
|
||||
const loginUrl = new URL('/login', request.url);
|
||||
loginUrl.searchParams.set('redirect', pathname);
|
||||
// Keep the query string, so a bounced /admin/photos?page=3 resumes where it was.
|
||||
loginUrl.searchParams.set('redirect', `${pathname}${search}`);
|
||||
return NextResponse.redirect(loginUrl);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user