JWT Access and Refresh Token Strategy
Design short-lived access tokens and rotating refresh-token sessions with revocation, browser protections, and key rotation.
On this page
An access token answers whether a request may call an API now. A refresh token lets a client obtain another access token later. Giving both tokens the same long lifetime removes that separation and makes a stolen API credential useful for much longer.
JWT is a token format, not an automatic security architecture. Signed JWT claims are normally readable, bearer tokens work for whoever possesses them, and a refresh-token design with rotation or revocation is intentionally stateful.
Give each token one job
| Token | Sent to | Typical contents | Lifetime |
|---|---|---|---|
| Access token | Resource API | subject, issuer, audience, scope, expiry, token ID | Short |
| Refresh token | Authorization/session endpoint | Usually an opaque random value or narrowly scoped token | Longer, bounded |
The actual lifetimes depend on account risk, device type, reauthentication policy, and incident response requirements. A ten-minute access token and multi-day refresh session are examples, not defaults for every application.
Keep access-token claims minimal. Validate the signature algorithm, key, iss, aud, exp, and applicable nbf; authorize the route using server-defined permissions. Do not place passwords, secrets, or unnecessary personal data in a JWT payload.
Model refresh tokens as device sessions
One user can have a phone, laptop, and shared workstation. Store each login as a separate session so the user can revoke one device without ending all others:
CREATE TABLE auth_session (
id uuid PRIMARY KEY,
user_id uuid NOT NULL,
family_id uuid NOT NULL,
refresh_token_hash bytea NOT NULL UNIQUE,
created_at timestamptz NOT NULL,
last_used_at timestamptz,
expires_at timestamptz NOT NULL,
revoked_at timestamptz,
replaced_by uuid,
user_agent_label text
);Store a keyed hash or cryptographic digest of a high-entropy random refresh token rather than its usable plaintext. A database leak then does not immediately reveal the bearer value. Exact hashing design depends on token entropy and threat model; password hashes need a slow password KDF, while uniformly random tokens can be looked up with a secure keyed hash.
Redis can hold session state with expiry for fast lookup, but persistence, replication, eviction policy, and outage behavior must match the revocation guarantee. PostgreSQL offers durable audit relationships. Some systems use both with an explicit source of truth.
Rotate on every refresh
A secure refresh flow is transactional:
- Receive the refresh credential over TLS.
- Hash it and lock or atomically consume its session row.
- Reject expired, revoked, or already replaced tokens.
- Issue a new short-lived access token and a new random refresh token.
- Store the new hash and mark the old row as replaced in one transaction.
- Return the new pair and overwrite the browser cookie.
OAuth 2.0 Security Best Current Practice requires public clients that receive refresh tokens to use sender-constrained tokens or refresh-token rotation to detect replay. With rotation, reuse of an invalidated token indicates that either the client or an attacker presented an old credential. Revoke the active token family and require authentication again; the server cannot safely assume which party is legitimate.
Handle simultaneous refresh requests deliberately. Two browser tabs can submit the same token nearly together. Atomic consumption prevents both from minting independent descendants. A narrowly bounded grace mechanism can improve reliability, but it weakens strict replay detection and must not allow unlimited reuse.
Cookies versus browser storage
For a browser application, a common design keeps the refresh token in a cookie such as:
Set-Cookie: __Host-refresh=<opaque-value>; Path=/; HttpOnly; Secure; SameSite=Lax; Max-Age=604800HttpOnlyprevents ordinary JavaScript from reading the cookie.Securerestricts it to HTTPS.SameSitecontrols cross-site sending; chooseStrict,Lax, orNonefrom the real navigation and domain requirements.- The
__Host-prefix requiresSecure,Path=/, and noDomain, narrowing cookie scope.
HttpOnly reduces token theft through XSS but does not make an XSS vulnerability harmless: malicious code can still make authenticated requests from the page. A cookie is sent automatically, so protect state-changing and refresh endpoints against CSRF using an appropriate combination of SameSite policy, Origin/Referer validation, and CSRF tokens. SameSite=None also requires Secure and generally needs stronger explicit CSRF protection.
Web storage is readable by JavaScript in the origin, so XSS can extract a long-lived refresh token. If architecture constraints require JavaScript-held access tokens, keep them in memory where practical, minimize lifetime and scope, and enforce a strong content-security and dependency policy. A backend-for-frontend can keep browser tokens server-side.
Native and mobile clients use platform secure storage and authorization patterns rather than browser cookie assumptions.
Logout and revocation
Logout should revoke the current refresh session server-side and expire the cookie. “Log out all devices” revokes every session or token family for the user. Password changes, account disablement, suspected theft, or key compromise may also trigger broader revocation.
Already issued self-contained access tokens normally remain valid until expiry unless every API checks a denylist or session version. That is why access tokens are short-lived. For high-risk actions, perform fresh authorization against current server state or require reauthentication rather than trusting an old claim.
Signing-key rotation
Use an explicit allowed algorithm; never accept the token's alg without library policy. With asymmetric signing, include a kid, publish or distribute current verification keys securely, and overlap old and new public keys until tokens signed by the old key expire. Then remove the retired key.
Protect private keys in a secret manager or key-management service, separate development and production issuers, and rehearse emergency rotation. Verifiers must bound JWKS cache time and handle unknown key IDs without accepting unsigned or algorithm-switched tokens.
Common implementation mistakes
- Giving access and refresh tokens the same long expiration.
- Storing plaintext refresh tokens in the database.
- Rotating the value but not retaining the family relationship for reuse detection.
- Treating logout as deleting browser state only.
- Storing long-lived browser tokens in
localStoragewithout accepting the XSS exposure. - Using cookies without a CSRF design.
- Verifying a signature but ignoring issuer, audience, expiry, or allowed algorithm.
- Putting current roles in a long-lived token and assuming permission changes apply immediately.
- Logging bearer tokens, cookies, or complete authorization headers.
The JWT Decoder can inspect sanitized example claims locally, but decoding is not signature verification. For the token format and signing tradeoffs, read JWT authentication without mythology and Hashing vs Encryption vs Encoding.
Verification checklist
- Access tokens have narrow audience, scope, claims, and short expiry.
- Refresh tokens are high-entropy, hashed at rest, rotated atomically, and bounded in lifetime.
- Reuse revokes the active family and produces a security event without logging tokens.
- Browser cookie attributes and CSRF defenses match the deployment topology.
- Logout, password change, account disablement, and per-device revocation are tested.
- Signature, algorithm, issuer, audience, and time claims are all validated.
- Signing-key rotation works with an intentional verification-key overlap.
References
Documentation checked on 2026-08-12:
Related writing
- Hashing vs Encryption vs Encoding — The Differences Developers Must UnderstandA production-minded map of encoding, hashing, and encryption—salts, passwords, JWTs, Base64 myths, interview answers, and the mistakes reviewers catch.
- JWT authentication without mythology — rotations, revocation, and session ergonomicsSymmetric versus asymmetric verification, JWKS fleets, leaky storage pitfalls, and when opaque cookies outperform bearer tokens.
- Fix Nodemailer TLS Certificate Hostname ErrorsWhat ERR_TLS_CERT_ALTNAME_INVALID means when Nodemailer connects to an SMTP server, why it happens, and how to fix it without disabling certificate verification.