Repository navigation
Host-only kbase_session; read kbase_session_backup as a fallback - #53
Merged
Merged
Conversation
Production kbase-ui scopes kbase_session to .narrative.kbase.us and the Narrative scopes it to its own host, so a user signed in there reached other kbase.us hosts signed out. Both also write kbase_session_backup on .kbase.us; getToken now falls back to it. The backup is deleted only when its token is dead everywhere: after the revoke at sign-out, and when /api/V2/me answers 401 (which now also clears kbase_session; it previously stayed). The root gate's MFA rejection leaves it, since other kbase.us sites still accept that token.
kbase-ui and the Narrative each keep kbase_session on their own host. One written on .kbase.us reaches them as a second cookie of the same name, and they resolve the pair differently (kbase-ui takes the first, the Narrative's client the last), so they can act on different tokens. It also reaches ci, appdev and next, which run other auth services. The Domain attribute is now omitted unless COOKIE_DOMAIN sets one. The .kbase.us copy earlier builds wrote is expired on every write and clear, and migrateSharedCookie moves a session held only there onto this host at boot, using the expiry mirrored at sign-in.
The deletion hit any kbase_session on .kbase.us, whoever set it. Cookies this app wrote there under earlier builds now run to their expiry.
kbase_session_backup is shared with other kbase.us sites. A /me 401 or a sign-out now deletes it only when it holds the token that died, and a sign-out whose revoke failed leaves it. After a 401 on kbase_session, a different backup token is validated before the user is signed out. The login page used any session /me accepts as signed in, so a session without 2FA disabled the ORCID button while the root gate rejected it. useSignedInMe applies the gate's rule (MFA Used) there. The gallery still shows any session's username.
Every kbase.us host receives every .kbase.us cookie, so environments tell their session backups apart by name. BACKUP_COOKIE_NAME (default kbase_session_backup) sets which one is read; its delete names this host's parent domain. The cached tokenInfo was keyed without the token, so after /me fell back from a dead kbase_session to the backup, the gate read the old token's 2FA answer for the new one. It is now keyed by token. That fallback also broadcast `cleared:` to other tabs before signing in with the backup, leaving them signed out. Other tabs now hear only the outcome.
The cookie name is operator-set and went into a regex unescaped, so a name with `.` matched other cookies and one with `(` threw. A corrupt kbase_session told other tabs `cleared:` even when the backup then signed this tab in; it now says so only when no backup is left. A backup check that throws after kbase_session was cleared told no one; other tabs are now asked to re-check.
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.
Production kbase-ui keeps
kbase_sessionon.narrative.kbase.us(ui/src/features/auth/hooks.ts:41-46,ui/config.json), and the Narrative keeps it on its own host (narrative/kbase-extension/static/kbase/js/api/auth.js:12-21). Neither cookie reaches gen2.kbase.us. Both apps also write the token tokbase_session_backupon.kbase.us. Before this change, next-gen-ui wrote itskbase_sessionon.kbase.usand never read the backup.Host-only
kbase_sessionA
kbase_sessionon.kbase.usreaches narrative.kbase.us as a second cookie of that name, and the readers there take different ones:ui/src/common/cookie.ts:3-13narrative/.../api/auth.js:90-97self.cookies.getauthhandlers.py:52The cookie now has no Domain attribute unless
COOKIE_DOMAINsets one. Cookies earlier builds wrote on.kbase.usare left to expire, up to 14 days.kbase_session_backupkbase_session/api/V2/meanswers 401kbase_sessionin place.BACKUP_COOKIE_NAME, defaultkbase_session_backup. Everykbase.ushost receives every.kbase.uscookie, so environments tell their backups apart by name, as kbase-ui does (REACT_APP_KBASE_BACKUP_COOKIE_NAME). The name is matched literally..kbase.us.Cross-tab signals
A token switch sends other tabs one
set:orcleared:for the outcome, never an intermediatecleared:. This covers:/mefalling back fromkbase_sessionto the backup;kbase_session;set:and re-check.2FA
A session whose token did not use 2FA (
mfa !== 'Used') is not signed in anywhere in the app. The root gate already enforced this. The login page did not: it disabled the ORCID button for such a session while every gated route sent the user back to/login.useSignedInMeapplies the gate's rule, and the login page and its?redirectcheck use it. The gallery shows the username of any session/meaccepts.The cached tokenInfo is keyed by token. It was keyed without one, so after
/meswitched to the backup token, the gate read the old token's 2FA answer.Rancher
COOKIE_DOMAINfrom the gen2 workload. It is set tokbase.us, which keeps the old.kbase.uscookie.BACKUP_COOKIE_NAME.Checks
npm run lint,npm run format:check,npm run typecheck,npm run build,npx vitest run --dir src: exit 0, 236 tests.cookie.kbase.test.tsruns on ahttps://gen2.kbase.usorigin so parent-domain cookies apply. Each fix was reverted in turn and its test failed.The entrypoint renders
BACKUP_COOKIE_NAMEwhen set and leaves the placeholder, read as the default, when unset.