{"record":{"id":"5c7c0410713f5e50","repo":"toeverything/AFFiNE","slug":"auth-session-expired","errorCode":"auth_session_expired","errorMessage":"The auth session has expired.","messagePattern":"The auth session has expired\\.","errorType":"exception","errorClass":"AuthSessionHttpError","httpStatus":401,"severity":"warning","filePath":"packages/backend/server/src/core/auth/guard.ts","lineNumber":144,"sourceCode":"    const result = await this.resolveRequestSession(req, res, isPublic);\n    return result?.session ?? null;\n  }\n\n  private async resolveRequestSession(\n    req: Request,\n    res?: Response,\n    isPublic = false\n  ): Promise<AuthenticatedRequestSession | null> {\n    const bearer = req.headers.authorization\n      ? extractTokenFromHeader(req.headers.authorization)\n      : undefined;\n    if (bearer && isLikelyJwt(bearer)) {\n      try {\n        const session = await this.signInWithJwt(req, bearer, res, isPublic);\n        return session ? { type: 'jwt', session } : null;\n      } catch (err) {\n        if (err instanceof SessionAccessTokenError) {\n          throw new AuthSessionHttpError(err.code);\n        }\n        throw err;\n      }\n    }\n\n    const session = await this.signInWithCookie(req, res, isPublic);\n    return session ? { type: 'cookie_session', session } : null;\n  }\n\n  async signInWithJwt(\n    req: Request,\n    token: string,\n    res?: Response,\n    isPublic = false\n  ): Promise<Session | null> {\n    if (req.session && req.authType === 'jwt') return req.session;\n    const session = await this.accessTokens.verify(token);\n    const versionAllowed = await this.checkUserSessionClientVersion(","sourceCodeStart":126,"sourceCodeEnd":162,"githubUrl":"https://github.com/toeverything/AFFiNE/blob/26c515e050211269e911f7d9cfe162a26c83ed98/packages/backend/server/src/core/auth/guard.ts#L126-L162","documentation":"Surfaced when `AccessTokenService.verify` throws `SessionAccessTokenError('AUTH_SESSION_EXPIRED')`: the auth session's `idleExpiresAt`, `absoluteExpiresAt`, or the underlying user session's `expiresAt` is in the past. Unlike error 158 the token signature/exp is fine, but the session it represents has lapsed. HTTP 401.","triggerScenarios":"The user was idle longer than the idle-expiry window, the absolute session lifetime elapsed, or the user session itself expired — all while still presenting a syntactically valid access token.","commonSituations":"User away from the app past the idle timeout, a long-lived absolute session cap reached, or the server-side session was expired but the client kept the token.","solutions":["Re-authenticate the user — refresh will fail because the session is expired, so a full sign-in is required.","Raise idle/absolute expiry in config if the timeout is too aggressive for your users.","Implement client-side session-lifetime awareness to prompt re-auth gracefully."],"exampleFix":"// before\ntry { await api() } catch (e) { if (e.code === 'auth_session_expired') throw e; }\n\n// after\ntry {\n  await api();\n} catch (e) {\n  if (e.code === 'auth_session_expired') {\n    await signOut();\n    redirect('/sign-in?reason=session_expired');\n  }\n}","handlingStrategy":"try-catch","validationCode":null,"typeGuard":null,"tryCatchPattern":"if (res.status === 401) {\n  const body = await res.clone().json().catch(() => ({}));\n  if (body.code === 'auth_session_expired') {\n    // refresh will fail; the session is gone — full re-auth needed\n    await signOut();\n    redirect('/sign-in?reason=session_expired');\n  }\n}","preventionTips":["Prompt re-authentication when the idle/absolute session window is close to expiring.","Do not attempt refresh on auth_session_expired — it will fail; go straight to sign-in.","Tune idle/absolute expiry to match user expectations if timeouts are too aggressive."],"tags":["authentication","session","expired","re-auth"],"backgroundTag":null,"analyzedSha":"26c515e050211269e911f7d9cfe162a26c83ed98","analyzedAt":"2026-08-12T13:15:16.447Z","schemaVersion":2},"datasetVersion":"2026-08-12T23:17:12.415Z"}