toeverything/AFFiNE · warning · AuthSessionHttpError

auth_session_expired

auth_session_expired

Error message

The auth session has expired.

What it means

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.

Source

Thrown at packages/backend/server/src/core/auth/guard.ts:144

    const result = await this.resolveRequestSession(req, res, isPublic);
    return result?.session ?? null;
  }

  private async resolveRequestSession(
    req: Request,
    res?: Response,
    isPublic = false
  ): Promise<AuthenticatedRequestSession | null> {
    const bearer = req.headers.authorization
      ? extractTokenFromHeader(req.headers.authorization)
      : undefined;
    if (bearer && isLikelyJwt(bearer)) {
      try {
        const session = await this.signInWithJwt(req, bearer, res, isPublic);
        return session ? { type: 'jwt', session } : null;
      } catch (err) {
        if (err instanceof SessionAccessTokenError) {
          throw new AuthSessionHttpError(err.code);
        }
        throw err;
      }
    }

    const session = await this.signInWithCookie(req, res, isPublic);
    return session ? { type: 'cookie_session', session } : null;
  }

  async signInWithJwt(
    req: Request,
    token: string,
    res?: Response,
    isPublic = false
  ): Promise<Session | null> {
    if (req.session && req.authType === 'jwt') return req.session;
    const session = await this.accessTokens.verify(token);
    const versionAllowed = await this.checkUserSessionClientVersion(

View on GitHub (pinned to 26c515e050)

Solutions

  1. Re-authenticate the user — refresh will fail because the session is expired, so a full sign-in is required.
  2. Raise idle/absolute expiry in config if the timeout is too aggressive for your users.
  3. Implement client-side session-lifetime awareness to prompt re-auth gracefully.

Example fix

// before
try { await api() } catch (e) { if (e.code === 'auth_session_expired') throw e; }

// after
try {
  await api();
} catch (e) {
  if (e.code === 'auth_session_expired') {
    await signOut();
    redirect('/sign-in?reason=session_expired');
  }
}
Defensive patterns

Strategy: try-catch

Try / catch

if (res.status === 401) {
  const body = await res.clone().json().catch(() => ({}));
  if (body.code === 'auth_session_expired') {
    // refresh will fail; the session is gone — full re-auth needed
    await signOut();
    redirect('/sign-in?reason=session_expired');
  }
}

Prevention

When it happens

Trigger: 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.

Common situations: 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.

Related errors


AI-assisted analysis of toeverything/AFFiNE@26c515e050 (2026-08-12). Data as JSON: /api/errors/5c7c0410713f5e50. Report an issue: GitHub.