V3 realtime sessions use short-lived type=access JWTs for gateway handshakes
and one-time-use type=refresh JWTs for silent renewal. The release gate is
v3-jwt-refresh-rotation.v1, backed by
V3/security/jwt-refresh-rotation-validation.json and
pnpm verify:v3 jwt-refresh-rotation.
Enforcement#
- Refresh tokens require a signed
jti,familyId,sessionId, andgeneration. - A refresh token can rotate exactly once. Rotation emits a new access JWT and a
new refresh JWT, then marks the replaced refresh
jtirevoked. - Reusing a replaced refresh token revokes the whole refresh-token family.
- Explicitly revoked refresh tokens fail before any new pair is minted.
- The refresh path rejects
type=accessJWTs; gateway handshakes continue to reject non-access JWTs.
Verification#
The Rust tests in apps/v3/lilith-realtime-gateway/src/lib.rs cover initial
issuance, single-use rotation, rotated access-token authentication, replay
rejection, explicit revocation, and access-token rejection at the refresh
endpoint. The analytics manifest mirrors those scenarios so release checks fail
closed if the implementation, evidence, package script, or TODO traceability
drifts.