You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
Session store drops the CSRF secret when it updates an existing session #6831
KnexSessionStore.set() writes a session with insert … onConflict(id).merge([...]), and csrfToken is not in the merge list (backend/src/sessions/knex-session-store.ts:120-132 on develop at f199a28; the list arrived with 8f4c1ae17). The CSRF secret is therefore only written when the session row is first inserted. A token generated for a session that already exists is never persisted, and the next state-changing request to the private API fails with 403 Missing csrf secret.
Reproduction
Measured on develop at f199a28, backend built from source, sqlite, one OIDC provider configured:
GET /api/private/auth/oidc/<id> 302 saves the session (pendingUser), no CSRF secret
GET /api/private/csrf/token 200 generates a secret for that existing session
DELETE /api/private/auth/pending-user 403 {"statusCode":403,"message":"Missing csrf secret"}
(with the token from the previous step in the csrf-token header)
The first request only needs to reach the redirect; no identity provider round trip is involved. The same 403 appears on PUT /api/private/auth/pending-user at the end of a complete first OIDC login, when the token is requested after the login started. In the database the affected session rows have csrf_token set to NULL.
When it bites
Sessions use saveUninitialized: false, so a row exists only once something modifies the session. If a token is requested first, the row is inserted with its secret and later updates leave it alone, which is why most flows work. The failure needs a session that was saved before the first token request, and GET /api/private/auth/oidc/:id is one path that does that.
What I have not measured: a real browser. The frontend requests the token lazily (frontend/src/redux/csrf-token/methods.ts) and logs in or registers a guest on load (components/application-loader/initializers/login-or-register-guest.ts), which normally creates the session row with a secret before any OIDC login starts. So I would expect browsers with guest access enabled not to see this, and I cannot tell you whether a configuration without guest access does.
Fix
Add FieldNameSession.csrfToken to the merge list. Pull request to follow.
Activity
ErikMichelson commentedon Sep 25, 2026
Thanks for reporting and providing a fix! We'll look into it soon.