Flow
How the page guard decides
1Public page?
Exact path or a real sub-path of a public page skips the check.
2Token there?
No token means a redirect to sign-in that remembers where you were going.
3Ask the auth server
One request, one reply shape, and the reply must say valid.
4Valid
The page loads.
5Clear no
Redirect to sign-in.
6Couldn't check
Send a 503 and leave the cookie alone.
The auth middleware was set up so that if the auth server went down for a minute, everyone signed in would get kicked to the sign-in page. Their sessions were still good. The page just couldn't tell.
I'm building an SDK for my own auth service. Its Next.js part has middleware that guards pages and helpers that tell the server code who the user is. My first change that day made both of them ask the auth server whether a token is real, instead of just checking that a cookie exists. Good change. The helper that did the asking had a problem.
Two kinds of "no"
The helper returned a user or nothing. It returned nothing for a fake token, an expired token, a server error, a dropped connection, or a garbled reply. The first two are about the user. The last three are about my servers. The middleware treated every nothing as "go sign in".
So an outage would look like a mass logout. People would land on a sign-in page that needs the same dead server. Probably they'd retry, add load, and blame their password.
Yes, no, and "I couldn't check"
The next commit gave the helper three answers. If the server says the token is valid, you get a user. If the server clearly says no, you get nothing. If the server errors, can't be reached, or sends junk, the helper throws a special "unavailable" error.
The middleware catches that error and sends back a 503, which means "try again soon". It doesn't redirect and doesn't touch the cookie. The server helpers pass the error up instead of saying nobody is signed in. The middleware needs to handle the new error.
The middleware catches the unavailable error and answers with a 503, and only a real nobody gets redirected to sign in.
A 401 would be wrong here, because a lot of client code drops its token on a 401.
A lookalike path and plain HTTP
Public pages were matched by prefix, so any path that started like the sign-in page skipped the check. Now it has to match exactly or be a real sub-path. The server address must also be https unless it's localhost.
A faked server and a wrong route
The tests use a faked server. They don't cover a server that hangs, and a not-found still counts as a firm no, so a wrong address in config would look like every user got rejected. None of this has seen a real outage.
The browser client is the bigger problem. In the same commit, its restore step started deleting the stored token on any failure, outages included. So the half of the kit that runs in the browser now treats an outage as a logout, the mistake I just fixed in the server half, and it goes further by throwing the token away.