fix(auth): bring a deep link back to its page after signing in

A home-screen shortcut, a notification tap or a bookmark opened without
a session landed on the sign-in page with a bare URL, and after signing
in the person was on the dashboard instead of the page they asked for.
The sign-in page already honoured a sanitised `next`; neither redirect
set one.

The proxy now passes the request's own path and query as `next` (the
bare start page goes without one). The shell does the same when the
account answer ends a session on a protected page, except after a
deliberate sign-out: the marker a confirmed session leaves is gone by
then, so the next person on the device starts from a bare sign-in page
rather than the page the previous one left.
This commit is contained in:
Marc-André Bombeck committed 2026-11-11 21:14:04 +01:00
1 parent 75b879279f
commit 6c5a6eacbb
7 files changed
+152 -37

No files matched your search

+9 -12
View File
@@ -565,20 +565,17 @@ export function proxy(request: NextRequest) {
const isSessionGatedPage = !isApiRoute && !isStaticFile && !isPublic;
if (isSessionGatedPage) {
if (!readSessionCookie(request.cookies)) {
return applyBaselineSecurityHeaders(
NextResponse.redirect(new URL("/auth/login", request.url)),
);
// Back here after signing in; the sign-in page re-checks `next`.
const signIn = new URL("/auth/login", request.url);
const here = `${pathname}${request.nextUrl.search}`;
if (here !== "/") signIn.searchParams.set("next", here);
return applyBaselineSecurityHeaders(NextResponse.redirect(signIn));
}
// v1.4.22 — server-side onboarding redirect. Previously the
// `<AuthShell>` ran this in a post-hydration `useEffect`, so a user
// with `onboardingCompletedAt === null` briefly saw the dashboard
// flash before the redirect fired. The auth flows (login, passkey,
// register, /api/auth/me) keep an `hl_onboarding` cookie in sync
// with the DB state; the proxy reads it without a DB roundtrip so
// the redirect lands on the first server response. The /onboarding
// page itself is in PUBLIC_PATHS above, so this branch only runs
// for the surfaces that need to redirect away.
// The onboarding redirect, here so it lands on the first response with no
// dashboard flash. The auth flows (login, passkey, register,
// /api/auth/me) keep the `hl_onboarding` cookie in step with the DB, so no
// DB round trip; `/onboarding` itself is public above.
const onboardingPending =
request.cookies.get("hl_onboarding")?.value === "pending";
// v1.4.22 — exact match the redirect