Access token vs. refresh token

Two keys with different jobs: a short-lived one that opens API calls, and a long-lived one whose only job is minting more of the first.

why do I have two tokensdifference between access and refresh tokenwhich token do I send with my requestsdo I send both tokens every timeacess token vs refresh tokenone token expires fast and the other doesn'tshort lived vs long lived tokenwhich one goes in the Authorization header

See it

Live demo coming soon

What it is

Two tokens, two jobs. The access token is the one you spend: it rides along on every API call in the Authorization header, lives 5 to 60 minutes, and is usually a signed JWT your API can verify by signature alone with no database round trip. The refresh token is the one you keep: it goes only to the auth server's token endpoint, lives days to months, and is usually an opaque random string whose hash sits in your database so it can be looked up and killed.

The split exists to buy two things that fight each other. Stateless access tokens make API calls fast, but you cannot un-issue them. So you keep their lifetime short enough that a leak has a small blast radius, and you hand out a separate, revocable, carefully-stored credential to cover the long tail of the session. Short and fast for calls, long and controllable for renewal.

Gotcha most people hit: revoking a refresh token does not log anyone out right away. Any access token already issued keeps working until it expires, which is the entire reason to keep that window at 15 minutes instead of 24 hours. Two related mistakes: sending the refresh token to your product API (it belongs to the auth server only), and stuffing both tokens in localStorage, which erases the security difference between them.

Ask AI for it

Set up a two-token auth scheme. Issue an access token as a JWT with a 15-minute expiry, containing sub, org id, roles, iss, aud, and jti, sent on every API request as 'Authorization: Bearer <token>' and verified locally with no database lookup. Issue a refresh token as a 32-byte random opaque string with a 30-day expiry, stored hashed server-side and delivered as an HttpOnly, Secure, SameSite cookie scoped to the refresh endpoint. Accept the refresh token at POST /auth/refresh only, never on resource routes, and return both a new access token and its expiry in seconds so the client can refresh proactively 60 seconds before expiry.

You might have meant

bearer tokenrefresh tokenrefresh token rotation and token revocationjwtsession