fix(gateway): accept the __Secure- prefixed NextAuth session cookie - #475
fix(gateway): accept the __Secure- prefixed NextAuth session cookie#475mrrobertkent wants to merge 1 commit into
Conversation
|
Correcting my own claim in the description above, having now tested this with a real browser session rather than a fabricated token. I wrote that "with the fix in place, a browser request carrying With this patch applied and a genuine session, the gateway gets past the cookie lookup and then fails one step later: Symbol 46 is So there are two independent problems on the browser→gateway session path, and this PR only addresses the first:
That reframes things. This change is still correct and still required — without it the gateway never even finds the cookie — but on its own it does not make session auth work, and I don't want the description overstating it. Fixing (2) properly means the gateway deriving the encryption key from Given that, #474 looks like the better path for the underlying problem: having the web app attach an API key avoids the token format question entirely, and closes #263 at the same time. I'm happy for this to be closed in favour of that, or kept as the narrow cookie-name fix if the session path is worth repairing on its own merits. Maintainers' call — I have no stake in which. Apologies for the overstated claim. |
|
Update after running #474 in production: with its web half applied, the browser sends That makes this optional. It is still a real bug — without it the gateway cannot find the cookie at all on a TLS deployment — but it repairs one step of a path whose next step (the JWE/JWS mismatch) is unfixed, so on its own it moves the failure from "cookie not found" to "JWT decode failed" and no further. Happy either way: close it as superseded, or keep it as a narrow correctness fix if the session path is worth repairing eventually. No preference from me, and no need to spend review time on it ahead of #474. |
I have read the CONTRIBUTING.md file.
YES
What kind of change does this PR introduce?
Bug fix.
What is the current behavior?
On a self-hosted instance running multi-user mode (
NEXTAUTH_SECRETset) and served over HTTPS, every browser call to the gateway returns401. That covers vault pair/status, pending approvals, approval decisions, and cache invalidation — so the 1Password and Bitwarden panels, the approvals UI, and the 1Password value picker are all unusable, while the rest of the dashboard works normally.validate_oauthreads the session cookie by exact name:Auth.js prefixes that cookie with
__Secure-whenever it considers the deployment secure, which it derives from the scheme of the resolvedAUTH_URL/NEXTAUTH_URL. A self-hosted instance cannot avoid this: OAuth providers require anhttpsredirect URI for anything other than localhost (Google documents the rule explicitly), so the single variable that makes login work also renames the cookie. The gateway then never finds it and logsoauth auth: session token cookie not found.Local-mode installs are unaffected, because
validate_localnever inspects the cookie — which is likely why this has gone unnoticed.Controlled reproduction
Same request, same (fabricated) JWT, only the cookie name differs:
And the same instance, over HTTPS, confirming which name a browser is actually sent:
What is the new behavior?
The lookup accepts either spelling, via a small helper:
The bare name is checked first, so http/localhost installs keep their existing single-comparison path and behaviour is unchanged for them. Four unit tests cover the bare name, the
__Secure-prefixed name, precedence when both are present, and neither present.Additional context
Found while running a self-hosted instance behind a reverse proxy with TLS and an external IdP. It is reachable from any edition that can run in
oauthmode over HTTPS, and it becomes considerably easier to hit alongside #430, which lets self-hosters use a non-Google IdP and so brings more TLS deployments into multi-user mode.#474 would also resolve this, by having the web app attach an API key so the gateway never falls through to the cookie. The two are complementary rather than competing: this change makes the documented session path work as intended and is a few lines, while #474 additionally closes the local-mode trust gap in #263. Happy to close this if #474 is the preferred direction.
Verification
Run against
apps/gateway(musl toolchain, matchingdocker/Dockerfile):cargo fmt --check— cleancargo clippy --all-targets— no new warningscargo test auth::— 7 passed (3 pre-existing, 4 new), 0 failedAlso verified on a live deployment: with the fix in place, a browser request carrying
__Secure-authjs.session-tokenreaches JWT validation instead of being rejected as missing.It does not, on its own, make session auth work — see the correction in the comments. Auth.js issues an encrypted (JWE) session token, while
validate_oauthdecodes withjsonwebtokenunderAlgorithm::HS256, which expects a signed JWS, so validation fails one step later withBase64 error: Invalid symbol 46. That is a second, independent problem on the same path and out of scope here. This PR fixes the cookie lookup only, which is a prerequisite either way.No TypeScript is touched, so
pnpm check/pnpm buildare unaffected by this change.