fix(auth): answer 503 when the session store cannot be read

The cookie resolvers folded a failed query into null, so a database restart
answered 401 and every client discarded a good credential. The lookup now
raises SessionStoreUnavailableError, which reaches the wire as 503 with
auth.session.unavailable. Logout still clears the cookie on a failed lookup
and records a warning.
This commit is contained in:
Marc-André Bombeck committed 2026-10-20 05:43:58 +02:00
1 parent 9af22f2ab2
commit c7f69fc212
7 files changed
+198 -44

No files matched your search

+27
View File
@@ -62,8 +62,35 @@ export const AUTH_ERROR_CODES = {
* the user out, which is the opposite of what the other 401 codes ask for.
*/
mfaCode: "auth.mfa.code_invalid",
/**
* The session store could not be read, so the request is neither signed in
* nor signed out. 503, not 401: a client that treats this as "signed out"
* drops a perfectly good session because the database blinked. Retry.
*/
sessionUnavailable: "auth.session.unavailable",
} as const;
/**
* The session lookup failed, as opposed to finding nothing.
*
* Raised by the cookie resolver in `src/lib/auth/session.ts` when the query
* itself throws — a dropped connection, a pool timeout, a failover. Answering
* that with 401 told every client to discard its credential and sign in again
* for a fault on the server's side, and a reload during a database restart
* signed the person out. The cause rides along for the wide event.
*/
export class SessionStoreUnavailableError extends HttpError {
constructor(cause: unknown) {
super(
503,
"Sign-in could not be checked right now. Try again shortly.",
AUTH_ERROR_CODES.sessionUnavailable,
);
this.name = "SessionStoreUnavailableError";
this.cause = cause;
}
}
/**
* v1.36.0 — the two refusals the acting-account resolver can raise.
*