Skip to content

JWT Access and Refresh Tokens — Complete Session Management Guide

DodaTech Updated 2026-06-28 2 min read

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

  1. Why are access tokens short-lived?
  2. How does refresh token rotation work?
  3. What happens when a refresh token expires?
  4. How do you revoke all sessions for a user?
  5. 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