fix(auth): bind accessToken cookie + JWT to a 7-day TTL#17
Merged
Conversation
Outline's accessToken cookie was hardcoded to 3 months
(addMonths(new Date(), 3)) at three call sites — outliving the rest of
the foss-server-bundle's 7-day session window. After a stack-wide
session expiry users would stay signed in to Outline alone.
Changes:
- Export JWT_COOKIE_TTL_DAYS = 7 from server/utils/authentication.ts as
a single source of truth (with rationale in a docstring).
- Use addDays(new Date(), JWT_COOKIE_TTL_DAYS) at all three mint sites:
- server/middlewares/authentication.ts (FORWARDAUTH login)
- server/routes/auth/index.ts (/auth/redirect)
- server/utils/authentication.ts (signIn callback)
- Fix a pre-existing upstream issue at /auth/redirect: getJwtToken was
called with no expiresAt arg, producing a JWT the validator at
utils/jwt.ts:47 never rejects (claim missing → check skipped). Now
passes `expires` into both getJwtToken and the cookie set, matching
the pattern the other two paths already use.
- Tests cover both halves:
- middlewares/authentication.test.ts asserts the FORWARDAUTH cookie's
expires is ~now + JWT_COOKIE_TTL_DAYS (±60s).
- routes/auth/index.test.ts asserts /auth/redirect mints a JWT whose
expiresAt claim is set and ~now + JWT_COOKIE_TTL_DAYS (±60s).
In future, lift JWT_COOKIE_TTL_DAYS to an env var if deployment-specific
control is needed.
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.
Summary
Outline's
accessTokencookie was hardcoded to 3 months (addMonths(new Date(), 3)) at three call sites — outliving the rest of thefoss-server-bundle's 7-day session window. After a stack-wide session expiry users would stay signed in to Outline alone.Additionally, the
/auth/redirecthandler was minting JWTs with noexpiresAtclaim (getJwtToken(undefined, service)), making the token replayable indefinitely if it ever left the cookie. The validator atserver/utils/jwt.ts:47silently skips the expiry check when the claim is missing.Changes
JWT_COOKIE_TTL_DAYS = 7fromserver/utils/authentication.tsas a single source of truth (with rationale in a docstring).addDays(new Date(), JWT_COOKIE_TTL_DAYS)at all three mint sites:server/middlewares/authentication.ts(FORWARDAUTH login)server/routes/auth/index.ts(/auth/redirect)server/utils/authentication.ts(signIncallback)/auth/redirectto passexpiresinto bothgetJwtTokenand the cookie option, so the JWT and cookie die together. Matches the pattern the other two paths already use.jwtToken === ctx.state.auth.tokenheuristic at/auth/redirect(which relied on session JWTs being deterministic — no longer true after theexpiresAtfix) with an explicit type check:getJWTPayload(ctx.state.auth.token).type !== "transfer". Direct, intent-revealing.Tests
server/middlewares/authentication.test.ts— asserts the FORWARDAUTHaccessTokencookie'sexpiresis~now + JWT_COOKIE_TTL_DAYS(±60s skew).server/routes/auth/index.test.ts— asserts/auth/redirectmints a JWT whoseexpiresAtclaim is set and~now + JWT_COOKIE_TTL_DAYS(±60s skew). JWT payload decoded with spec-correctbase64url.should prevent token extension by rejecting JWT tokenstest still passes via the new type check.Future
If deployment-specific control becomes needed, lift
JWT_COOKIE_TTL_DAYSto an env var (e.g.SESSION_TTL_SECONDS).