Revocation & security
Refresh-session revocation and access-token validity are separate concerns. Design your authentication flow around that boundary.
Revoke one device
List the user's active families and pass the chosen family's identifier:
const families = await sessions.listActiveSessionsForUser(userId);
const chosen = families[0];
if (chosen) {
await sessions.revokeSession(chosen.tokenHash);
}Verify that the requested family belongs to the authenticated user before revoking it through an HTTP endpoint. SessionTether does not enforce endpoint authorization.
Identifier semantics
Despite the parameter name refreshToken in the current method source, revokeSession() forwards its value directly to the store. Both SQL adapters expect the stable family tokenHash, not a raw refresh credential or the hash of an arbitrary rotated token. A successful validation also returns this identifier as familyId.
Revoke every device
await sessions.revokeAllSessionsForUser(userId);Use this after password reset, account recovery, or administrative logout when your application requires global renewal invalidation. Your application owns when to trigger it.
Access tokens after revocation
Already-issued access JWTs can still pass local verification until their expiration. In the SQLite example, access tokens last five minutes; the core library does not set this duration.
Logout also needs to clear the current client's credentials. Revoking server-side refresh state alone does not remove cookies from a browser.
Credentials and storage
The library stores token hashes rather than raw tokens. Raw refresh tokens still require secure transport and client handling. Passwords use the separate scrypt helpers; hashToken() is not a password-hashing function.
TLS, cookie policy, CSRF/origin checks, rate limits, account authentication, authorization, and reset delivery belong to the application. See the example for the repository's local development flow.
Implementation boundaries
Both SQL adapters lock the active family, then commit conditional consumption and replacement together. Family and user-wide revocation contend on that same row. If revocation wins, rotation returns revoked without consuming the token or creating a successor. If rotation wins, later revocation covers its successor. Responses can arrive after a later revocation; transaction ordering determines which operation won. Expiration is rechecked under the family lock using a fresh application-clock timestamp as the consumption decision point. At or after expiry, TokenExpiredError maps to expired without consuming the token or creating a successor. No expiration grace applies; expiry after the decision does not abort commit. There is no security-version mechanism in the core. See implementation status for the full boundary.
