fix: keep terminal stable across auth refresh
This commit is contained in:
@@ -119,6 +119,15 @@ export function runTests() {
|
||||
middlewareSource.indexOf("await refreshMiddlewareSession(request)"),
|
||||
"middleware must redirect no-cookie page requests without calling Supabase auth",
|
||||
);
|
||||
const terminalGateSource = middlewareSource.slice(
|
||||
middlewareSource.indexOf("async function handleTerminalGate"),
|
||||
middlewareSource.indexOf("async function handleSupabaseAuthGate"),
|
||||
);
|
||||
assert(
|
||||
terminalGateSource.includes("return response;") &&
|
||||
!terminalGateSource.includes("return redirectToLogin(request, pathname);\n}"),
|
||||
"terminal middleware must not navigate long-lived dashboards away when a session cookie exists but claims refresh is transiently unavailable",
|
||||
);
|
||||
assert(
|
||||
middlewareSource.includes("unauthorizedSupabaseSessionResponse()"),
|
||||
"middleware must reject no-cookie protected API requests without calling Supabase auth",
|
||||
|
||||
@@ -954,6 +954,18 @@ function ScanTerminalScreen() {
|
||||
data: { subscription },
|
||||
} = supabase.auth.onAuthStateChange(async (event, session) => {
|
||||
if (event === "SIGNED_OUT") {
|
||||
try {
|
||||
const {
|
||||
data: { session: currentSession },
|
||||
} = await supabase.auth.getSession();
|
||||
const accessToken =
|
||||
currentSession?.access_token || session?.access_token || null;
|
||||
if (accessToken) {
|
||||
const payload = await loadAuthProfile(accessToken);
|
||||
setProAccess((prev) => mergeAccessStateWithAuthPayload(prev, payload));
|
||||
return;
|
||||
}
|
||||
} catch {}
|
||||
setProAccess(createEmptyAccess(false));
|
||||
} else if (event === "TOKEN_REFRESHED" || event === "SIGNED_IN") {
|
||||
try {
|
||||
|
||||
@@ -65,4 +65,15 @@ export function runTests() {
|
||||
chartCanvasSource.includes('compact ? "min-h-[120px]" : "min-h-[220px]"'),
|
||||
"compact grid charts must not force desktop minimum heights that get clipped inside 3x3 terminal slots",
|
||||
);
|
||||
const signedOutBlock = dashboardSource.slice(
|
||||
dashboardSource.indexOf('if (event === "SIGNED_OUT")'),
|
||||
dashboardSource.indexOf('} else if (event === "TOKEN_REFRESHED"'),
|
||||
);
|
||||
assert(
|
||||
signedOutBlock.includes("await supabase.auth.getSession()") &&
|
||||
signedOutBlock.includes("mergeAccessStateWithAuthPayload(prev, payload)") &&
|
||||
signedOutBlock.indexOf("await supabase.auth.getSession()") <
|
||||
signedOutBlock.indexOf("setProAccess(createEmptyAccess(false))"),
|
||||
"terminal auth listener must re-check the current Supabase session before clearing access on SIGNED_OUT events",
|
||||
);
|
||||
}
|
||||
|
||||
@@ -104,8 +104,11 @@ async function handleTerminalGate(request: NextRequest): Promise<NextResponse> {
|
||||
return response;
|
||||
}
|
||||
|
||||
// Layer 1: Not logged in → redirect to /auth/login?next=/terminal
|
||||
return redirectToLogin(request, pathname);
|
||||
// A session cookie exists, but the edge/server refresh can occasionally fail
|
||||
// during a long-lived terminal tab. Do not navigate an active dashboard away
|
||||
// on a transient claims failure; the client can still verify via bearer auth
|
||||
// and render the in-product access gate if the session is truly gone.
|
||||
return response;
|
||||
}
|
||||
|
||||
async function handleSupabaseAuthGate(request: NextRequest) {
|
||||
|
||||
Reference in New Issue
Block a user