
Keep sessions usable while credentials rotate
Keep people signed in without treating a long-lived token as permanent authority. Wildo refreshes access through rotating credentials and checks the account’s current state before continuing the session.
A short retry window handles ordinary duplicate refreshes. Reuse outside that window triggers token withdrawal rather than silently extending access.
Example — Retry a refresh without losing the session
A refresh succeeds but its response is lost. Once the successor is cached, a prompt retry with the retired credential can receive that same successor. Replaying it after the grace window is treated differently.
For engineers
Configure session policy at the right level
Wonder Todos’ administrator type declares:
sessionDurationMinutes: 30,
maxConcurrentSessions: 3,
sessionDurationMinutes is the lifetime of the temporary sign-in episode, not the duration of the access JWT it eventually produces. Registration and invitation episodes are created with a 24-hour expiry; idle timeout and subsequent session-store updates also affect how long they remain usable. maxConcurrentSessions controls the number of authenticated sessions. JWT signing material and access/refresh token lifetimes are deployment-authored runtime settings.
Keep the refresh credential in its cookie
The standard client sends the refresh request with the HTTP-only refresh cookie. The endpoint takes an empty body; a JavaScript client should not read, store or submit the refresh token itself. Access-token updates are propagated to API clients and coordinated between same-origin tabs.
The controller reads the cookie after validating the request shape. Selected code from authentication-controller.backend.service.ts:
const ec = await this._getPreAuthExecutionContext();
RefreshTokenBodySchema.parse(req.body || {});
const refreshTokenValue = AuthControllerUtils.extractRefreshTokenFromCookie(req);
if (!refreshTokenValue) {
throw this.errorBuilder.buildError(ErrorType.VALIDATION, undefined, {
customMessageReference: ErrorCustomMessageReference.AUTHENTICATION_REFRESH_TOKEN_REQUIRED,
});
}
Follow the order of the backend checks
| Check | Why it precedes rotation |
|---|---|
| Token validity and live account | A valid signature does not keep a disabled account active |
| Authorization version | A session cannot retain an older authority snapshot |
| Account and session revocation | A retry cannot cross a withdrawal |
| Retired token and grace successor | A short duplicate can receive the already-issued successor |
AuthTokenIssuerBackendService.refreshAccessToken returns a cached successor when the predecessor is already marked as rotated and its grace entry exists. Concurrent refreshes select one successor in a Redis transaction that also records the retired credential and applies the winner’s session-limit effects. Losing requests receive the stored successor; they do not register extra sessions. If a response is lost after that transaction, a retry can recover the same tokens during the grace window. After the grace window expires, reuse of the retired credential writes the account-wide invalidation fence and reports a distinct reuse event. The raw token is not part of that signal.
Concurrent-session enforcement uses the shared session store and eviction path. A custom authentication integration must preserve these issuance and refresh paths; manually signing a replacement JWT would bypass the session lifecycle that makes the policy meaningful.