Table of Contents
- Why Tokens Exist
- Access Token
- Refresh Token
- Authentication Flow
- Why Not a Single Token
- Security Best Practices
- Token Storage Options
- Logout and Revocation
- Common Backend Mistakes
- JWT vs Session-Based Authentication
- When to Use Access & Refresh Tokens
- Reference Links
Why Tokens Exist
- HTTP is stateless.
- Tokens represent user identity across requests.
Access Token 🔑
Access tokens are generally distributed as JSON Web Tokens (JWTs), a small, self-contained format valued for its platform-neutrality and security.
When using access tokens for authorization:
- A client app asks the user for permission
- The authorization server issues an access token
- The user can access protected resources once validated
Key Points
- Used to access protected APIs
- Short-lived (typically 5–15 minutes)
- Sent with every request in the
Authorizationheader - Commonly implemented as JWT
- Contains user identity, roles/scopes, and expiration
Common Claims
| Claim | Purpose |
|---|---|
| exp | Token expiration time |
| iat | Token issued-at time |
| jti | Unique token identifier |
| iss | Token issuer |
| aud | Intended audience |
| typ | Token type (e.g., JWT) |
| sub | Subject (typically user ID) |
| azp | Authorized party (client ID) |
| sid | Session identifier |
| scope | Granted permissions / scopes |
Refresh Token 🔄
Refresh tokens are usually stored securely and used when the access token expires.
They allow users to obtain a new access token without re-authenticating.
Key Points
- Used to obtain new access tokens
- Long-lived (days or weeks)
- Not used for API access
- Stored securely (database + HttpOnly cookie)
- Enables seamless user sessions
Authentication Flow
Step 1: User Login
POST /login
Request
{
"username": "username",
"password": "password"
}
Response
{
"accessToken": "eyJhbGciOiJSUzI1NiIs...",
"refreshToken": "eyJhbGciOiJIUzUxMiIs..."
}
Step 2: Access Protected APIs
Authorization: Bearer <accessToken>
Step 3: Refresh Token Flow
POST /auth/refresh
Request
- No body required
- Refresh Token sent via cookie
Server Behavior
-
Validate Refresh Token:
- signature
- jti
- sid
- not revoked
Issue new Access Token
(Optional) Rotate Refresh Token
Response
{
"accessToken": "<NEW_ACCESS_TOKEN>",
"expiresIn": 900
}
Optional Rotation
Set-Cookie: refreshToken=<NEW_REFRESH_TOKEN>; HttpOnly; Secure; SameSite=Strict
API Endpoints
| Endpoint | Purpose |
|---|---|
| POST /auth/login | Authenticate user and issue tokens |
| POST /auth/refresh | Refresh access token |
| POST /auth/logout | Invalidate current session |
| POST /auth/logout-all | Invalidate all user sessions |
| GET /api/* | Access protected resources |
Why Not a Single Token
- Long-lived tokens increase security risks if compromised
- Short-lived tokens alone degrade user experience
- Combining both balances security and usability
Security Best Practices
- Keep Access Tokens short-lived
- Store Refresh Tokens securely (hashed in DB)
- Use Refresh Token rotation
- Revoke tokens on logout or password change
- Avoid storing tokens in LocalStorage
Token Storage Options
- Prefer HttpOnly, Secure cookies
- Use in-memory storage for Access Tokens
- Avoid LocalStorage due to XSS risks
Logout and Revocation
- Logout invalidates the Refresh Token
- Access Tokens expire naturally
- Refresh Token revocation enables logout from all devices
Common Backend Mistakes
- Storing Refresh Tokens in LocalStorage
- Using long-lived Access Tokens
- Not implementing Refresh Token rotation
- Leaving refresh endpoints unprotected
JWT vs Session-Based Authentication
- JWT is stateless and scalable
- Sessions are stateful and easier to revoke
- Token-based auth suits distributed systems
When to Use Access & Refresh Tokens
- Single-page applications (SPAs)
- Mobile applications
- Microservices and distributed architectures
Reference Links
This article was originally published by DEV Community and written by AliFathy-1999.
Read original article on DEV Community