SessionManagementStorage (and SessionLinkStorage for
links); the memory, SQLite, Postgres and MySQL adapters do. New returns ErrStorageMissingCapability
when a configured feature lacks its capability.
Config
Idle precision is the touch interval: a session can outlive its idle limit by
up to one interval.
End-user routes (RequireAuth)
GET /auth/sessionslists{id, deviceLabel, ipPrefix, createdAt, lastSeenAt, expiresAt, current}. IPs are masked to /24 (IPv4) or /48 (IPv6).DELETE /auth/sessions/{id}revokes one of the caller’s sessions (404 for anyone else’s).POST /auth/sessions/revoke-othersrevokes all but the current one and returns{revoked: n}.DELETE /auth/sessions/currentis unchanged.POST /auth/password/changeverifies the current password, revokes every session and sets a fresh cookie.
GET /admin/v1/organizations/{orgID}/sessions?user_id= now returns the user’s live sessions.
Rotation
A new token replaces the old one at login (unchanged), MFA completion (/auth/totp/verify, /auth/totp/recovery: the pending token dies and a new
cookie is set), and password change. Password reset already revokes all
sessions. TheAuth.RotateSession is exported for your own privilege changes.
The Go methods VerifyTOTP and ConsumeRecoveryCode still return the same
token; only the HTTP routes rotate.
Step-up
POST /auth/step-up with one of:
POST /auth/step-up/passkey/begin returns {options, challenge}; pass
the browser’s assertion back as assertion. A TOTP code that fails five times
revokes the session, same as the pending-2FA path.
Success sets Session.ElevatedUntil. Guard sensitive routes with
RequireRecentAuth(maxAge): it passes when the session logged in or stepped up
within maxAge, else 403 auth.recent_auth_required. Sessions tied to a
credential (session links) never count their creation time as a login.
Session links
Enable withConfig.SessionLinks. Mint on behalf of a user from your own
authorized code:
POST /auth/session-link/consume {"token": tok} exchanges it, once, for a
session cookie (ConsumeSessionLink is the Go form). POST, not GET, so link
previewers cannot burn it.
A session minted with a CredentialID is tied to it: CredentialChecker runs
at mint, at exchange, and on every session validation, with no caching. It
must return ErrCredentialRevoked for a revoked, expired or unknown
credential; that revokes the session. Any other error fails the request closed.
Call RevokeSessionsByCredential when you revoke the credential to cut
sessions immediately instead of lazily.
Long-lived streams
WatchSession(ctx, token, interval) returns a context cancelled (cause set)
when the session stops validating, including idle expiry and credential
revocation; checks do not count as activity. WatchSessionMiddleware(interval)
applies it to a request. It fails closed on any validation error.
Storage contract
storagetest.RunSessionManagement covers list, monotonic touch, bulk revoke,
elevation and single-use link consumption (including a concurrent-consume
race). storagetest.Run includes it when the backend implements both
capabilities. The Postgres and MySQL adapters implement them (migration 0018).