Files
AFFiNE-Mirror/packages/backend/server
Whitewater b22bc17bd0 fix(server): align native JWT session TTL with auth session TTL (#15210)
## Summary

This is a backend-only workaround for native/mobile sessions expiring
much earlier than the normal AFFiNE auth session.

Native JWT-backed sessions now use the existing `auth.session.ttl`
instead of the hard-coded 15-minute TTL.

No database migration, no new config, and no mobile client changes are
required.

## Background / Investigation

PR #15060 introduced native session exchange and JWT-backed native
sessions for mobile/desktop clients.

Relevant code introduced there:

- `packages/backend/server/src/core/auth/session-issuer.ts`
  - Native clients no longer receive normal auth cookies.
- `SessionIssuer` clears cookies for native clients and returns a native
session exchange code instead.

- `packages/backend/server/src/core/auth/native-exchange.ts`
- Native clients exchange the one-time code for a JWT-backed session
token.

- `packages/backend/server/src/core/auth/jwt-session.ts`
  - The JWT session implementation was introduced with:
    - `const JWT_SESSION_TTL = 15 * 60`
    - `expiresIn: JWT_SESSION_TTL`
    - normal `jwt.verify(...)` expiration enforcement

That means a native/mobile client that does not reconnect and
exchange/sign in again within 15 minutes can lose backend auth even
though the DB-backed AFFiNE user session is still valid for the normal
app session TTL, currently 15 days by default.

Web does not hit this path because web keeps using the normal
cookie-backed session issued by `AuthService`, whose expiration is based
on `auth.session.ttl`.

## Related Issues / PRs Checked

- Source PR: #15060
- Introduced native session exchange, JWT-backed sessions, native token
storage, and websocket JWT support.
- This PR appears to be the source of the hard-coded 15-minute native
JWT TTL behavior.

I did not find a public issue that directly reports "native JWT expires
after 15 minutes".

## What Changed

- Removed the hard-coded 15-minute native JWT TTL.
- Updated `JwtSessionService.sign()` to issue native JWTs with
`auth.session.ttl`.
- Kept `JwtSessionService.verify()` on normal JWT expiration
verification, so existing JWTs that already expired under the previous
15-minute `exp` need to be refreshed by signing in again.
- Kept the existing DB-backed session lookup:
- sign-out still revokes the native JWT by deleting the backing session
  - expired/deleted DB sessions still reject the JWT

## Why This Is A Workaround

A more complete long-term design would add a true refresh-token flow for
native clients, likely with persisted refresh tokens,
rotation/revocation semantics, and database changes.

This PR intentionally avoids that larger design. It restores the
expected mobile login lifetime for newly issued native JWTs by aligning
native JWT lifetime with the existing app session lifetime, while
preserving the current native exchange model, Keychain/Keystore storage,
and revoke-by-session behavior.

## Compatibility

- Backend only
- No DB schema change
- No mobile app change
- No new config
- Existing native JWTs that already expired under the old 15-minute
`exp` will still require signing in again.
- Newly issued native JWTs use `auth.session.ttl`.

## Verification

Latest verification after removing the extra native JWT TTL config:

- JWT session tests: 4 passed
- `yarn typecheck`: passed
- `lint-staged`: passed via `corepack yarn`
- `lint:ox`: passed via `corepack yarn`

Earlier broader checks on this branch also passed selected auth tests
and the websocket JWT auth subset.

<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->

## Summary by CodeRabbit

* **New Features**
* Session login tokens now follow the configured session lifetime, so
expiration behavior can be adjusted through app settings.

* **Bug Fixes**
* Improved consistency between token expiration and session expiry
checks.
* Added coverage for cases where a session is missing, expired, or the
session lifetime changes.

<!-- end of auto-generated comment: release notes by coderabbit.ai -->
2026-07-11 06:40:58 +08:00
..
2026-06-24 23:55:19 +08:00
2024-12-24 15:29:48 +08:00

Server

Get started

Install dependencies

yarn

Build Native binding

yarn affine @affine/server-native build

Run server

yarn dev

now you can access the server GraphQL endpoint at http://localhost:3000/graphql