JWT Access and Refresh Tokens — Complete Session Management Guide
In this tutorial, you will learn about JWT Access and Refresh Tokens. We cover key concepts, practical examples, and best practices to help you master this topic.
The access token and refresh token pattern uses short-lived access tokens (15 minutes) for API requests and long-lived refresh tokens (7-30 days) to obtain new access tokens without re-authentication.
What You'll Learn
You'll learn how to implement access and refresh token rotation, secure storage, and automatic token refresh.
Why It Matters
Short-lived access tokens limit damage if a token is stolen. Refresh tokens allow persistent sessions without storing passwords. This pattern balances security and user experience.
Real-World Use
A mobile banking app uses 5-minute access tokens and 7-day refresh tokens. If the phone is stolen, the access token expires quickly, and the bank can revoke the refresh token server-side.
sequenceDiagram
participant Client
participant Auth
participant API
Client->>Auth: POST /login
Auth->>Client: access_token (15min) + refresh_token (7d)
Client->>API: GET /data (Bearer access_token)
API->>Client: Data
Note over Client: Access token expires
Client->>Auth: POST /refresh (refresh_token)
Auth->>Client: new access_token + new refresh_token
Client->>API: GET /data (Bearer new access_token)
API->>Client: Data
Teacher's Mindset
Think of access tokens as cash in your wallet and refresh tokens as your ATM card. If you lose 20 dollars (access token), it is annoying but limited. If you lose your ATM card (refresh token), you call the bank to cancel it.
Implementation
import jwt
from datetime import datetime, timedelta
import secrets
SECRET = "your-secret-key"
ACCESS_EXPIRY = 15 # minutes
REFRESH_EXPIRY = 7 # days
def create_access_token(user_id):
return jwt.encode({
"sub": user_id,
"type": "access",
"iat": datetime.utcnow(),
"exp": datetime.utcnow() + timedelta(minutes=ACCESS_EXPIRY)
}, SECRET, algorithm="HS256")
def create_refresh_token(user_id):
token_id = secrets.token_hex(16)
return jwt.encode({
"sub": user_id,
"type": "refresh",
"jti": token_id,
"iat": datetime.utcnow(),
"exp": datetime.utcnow() + timedelta(days=REFRESH_EXPIRY)
}, SECRET, algorithm="HS256"), token_id
def refresh_access_token(refresh_token, token_store):
try:
payload = jwt.decode(refresh_token, SECRET, algorithms=["HS256"])
if payload["type"] != "refresh":
raise ValueError("Invalid token type")
if not token_store.is_valid(payload["jti"]):
raise ValueError("Token revoked")
token_store.rotate(payload["jti"])
new_access = create_access_token(payload["sub"])
new_refresh, new_jti = create_refresh_token(payload["sub"])
return new_access, new_refresh
except jwt.ExpiredSignatureError:
raise ValueError("Refresh token expired")
@app.route("/api/login", methods=["POST"])
def login():
user_id = authenticate(request.json)
access = create_access_token(user_id)
refresh, jti = create_refresh_token(user_id)
token_store.save(jti, user_id, datetime.utcnow() + timedelta(days=7))
return jsonify({
"access_token": access,
"refresh_token": refresh,
"expires_in": ACCESS_EXPIRY * 60
})
Common Mistakes
| Mistake | Fix |
|---|---|
| Long-lived access tokens | Keep access tokens under 15 minutes |
| Not rotating refresh tokens | Issue new refresh token on each use |
| Storing refresh tokens insecurely | Hash refresh tokens in database |
| No refresh token revocation | Maintain server-side revocation list |
| Refresh token never expires | Set maximum lifetime (7-30 days) |
Practice Questions
- Why are access tokens short-lived?
- How does refresh token rotation work?
- What happens when a refresh token expires?
- How do you revoke all sessions for a user?
- Why should refresh tokens be one-time use?
Challenge
Implement the complete access/refresh token pattern. Support: login (issues both tokens), token refresh (rotates refresh token), logout (revokes refresh token), and automatic retry on 401.
What's Next
Learn about OAuth 2.0 authorization code flow for delegated authorization.
Built by the developers of DodaTech
Doda Browser, DodaZIP & Durga Antivirus Pro