fix(auth): confirm a missed session on the write host before 401ing (9893 root cause)#1055
Merged
Merged
Conversation
…ing (9893 root cause) Follow-up to #1048, which fixed the symptom (a stray 401 no longer wipes the whole session). This addresses the root cause of the stray 401 itself. The auth middleware's per-request session-consistency check runs a plain, replica-routed SELECT. The session row is INSERTed on the write host at login (auth.CreateSessionAndJWT), so a read replica can momentarily return zero rows right after login (Galera apply lag) - which the middleware treats as an invalid session and overrides the response with a 401. Right after login a ModTools client fires a burst of authenticated requests, so one landing in that window gets spuriously 401'd; on /session that still forces a logout even after #1048. On a zero-row miss, re-confirm against the write host (.Clauses(dbresolver.Write), a no-op when no replica is configured) before deciding the session is invalid - the same read-after-write pinning already used in authority/stats.go and ~10 message/chat sites. The happy path (session found on the replica) is unchanged and adds no extra query. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01VXKgf7Xquudc6CwP2RN6jX
✅ Deploy Preview for golden-caramel-d2c3a7 ready!
To edit notification comments on pull requests, go to your Netlify project configuration. |
Resolve the only conflict (docs/members/assets/browse.png) by keeping master's version - a generated screenshot unrelated to this auth fix. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01VXKgf7Xquudc6CwP2RN6jX
# Conflicts: # docs/members/assets/browse.png
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Follow-up to #1048 (merged). #1048 fixed the symptom — a stray 401 no longer wipes the whole session and forces a relogin. This fixes the root cause of the stray 401, which the adversarial review correctly flagged was left unaddressed.
Root cause
iznik-server-go/user/authMiddleware.goruns a per-request session-consistency check as a plain, replica-routedSELECT ... FROM sessions JOIN users. The session row isINSERTed on the write host at login (auth.CreateSessionAndJWT), so a Galera read replica can momentarily return zero rows right after login (apply lag). The middleware treats zero rows as an invalid session and overrides the response with a 401.Right after login the ModTools client fires a burst of authenticated requests (chat poll, notification/work counts, …); any one landing in that replication window gets spuriously 401'd. On
/sessionthat still forces a logout even after #1048 — and each forced relogin mints a fresh session row, re-opening the window (the self-reinforcing loop heavy mods hit "several times a day").Fix
On a zero-row miss, re-confirm the lookup against the write host before deciding the session is invalid:
This is the same read-after-write pinning already used in
authority/stats.goand ~10message/chatsites..Clauses(dbresolver.Write)is a documented no-op when no replica is configured. The happy path (session found on the replica) is unchanged and adds no extra query — only a genuine miss pays for the confirming read.Testing
The race needs a lagging read replica, which the single-host test DB can't reproduce, so there's no new unit test; existing auth tests still cover the happy path (a valid session authenticates, and my change is a no-op there).
🤖 Generated with Claude Code