Web Dev

JWT Auth in FastAPI: Our Battle-Tested Implementation

A production-ready JWT authentication setup for FastAPI — access and refresh tokens, rotation, revocation, and the security details most tutorials skip.

TTaimoorAI & Backend Engineer
10 min read
J

Most JWT tutorials stop at “here is how to sign a token.” Production needs more: short-lived access tokens, refresh tokens, rotation, and a revocation story. Here is the FastAPI auth setup we actually ship, and the reasoning behind each decision.

Two tokens, two jobs

Use a short-lived access token (minutes) for API requests and a long-lived refresh token (days) to mint new access tokens. If an access token leaks, it expires fast; the refresh token lives in an HttpOnly cookie where JavaScript cannot read it.

from datetime import datetime, timedelta, timezone
import jwt  # PyJWT

def make_token(sub: str, minutes: int, secret: str) -> str:
    now = datetime.now(timezone.utc)
    payload = {"sub": sub, "iat": now, "exp": now + timedelta(minutes=minutes)}
    return jwt.encode(payload, secret, algorithm="HS256")

Refresh token rotation

Every time a refresh token is used, issue a new one and invalidate the old. If an attacker replays a stolen-but-already-rotated token, you detect reuse and can revoke the entire session family. This is the single highest-leverage upgrade over naive JWT auth.

The revocation problem

JWTs are stateless, which is great for scale and awkward for logout. The pragmatic answer is a small denylist (or a per-user token version) in Redis: check it on refresh, keep access tokens short so the window of risk is tiny. We wire Redis in via our standard Docker Compose template.

Storage: cookies vs localStorage

  • Refresh token HttpOnly; Secure; SameSite=Strict cookie. Inaccessible to JS, which neutralizes XSS token theft.
  • Access token → memory on the client. Never localStorage, which is readable by any injected script.

Hardening checklist

  • Always set exp; validate it on every request.
  • Pin the algorithm — reject alg: none outright.
  • Rotate signing secrets and support a key id (kid).
  • Rate-limit the login and refresh endpoints.

For the broader threat model, the OWASP Top 10 is the reference we hold our auth code against.

Key takeaways

  • Short access tokens + long refresh tokens, in an HttpOnly cookie.
  • Rotate refresh tokens and detect reuse.
  • Use a Redis denylist for real logout/revocation.
  • Pin the algorithm and follow OWASP.

Authentication is too important to improvise. Our backend engineering team ships this setup as a baseline — talk to us about hardening your API. See also our RBAC guide for what comes after authentication.

All articlesWritten by Taimoor · AI & Backend Engineer

Have a project that needs this kind of engineering?

We turn ideas into production software — AI, web, mobile, and cloud.

Start a Conversation