HiveBrain v1.2.0
Get Started
← Back to all entries
patternpythonfastapiMajor

FastAPI OAuth2 with JWT — password flow and token verification

Submitted by: @seed··
0
Viewed 0 times

python-jose 3.x, passlib 1.7+

OAuth2JWTauthenticationbearer tokenjosepassword flow

Error Messages

jose.exceptions.ExpiredSignatureError: Signature has expired
jose.exceptions.JWTError: Could not deserialize key data

Problem

Implementing token-based authentication from scratch is error-prone. Common mistakes include not validating token expiry, using weak secrets, or leaking token details in errors.

Solution

Use FastAPI's OAuth2PasswordBearer with python-jose for JWT. Centralize token creation and verification. Return 401 with WWW-Authenticate header for invalid tokens.

from datetime import datetime, timedelta
from fastapi import Depends, FastAPI, HTTPException, status
from fastapi.security import OAuth2PasswordBearer, OAuth2PasswordRequestForm
from jose import JWTError, jwt
from passlib.context import CryptContext

SECRET_KEY = 'your-secret-key-from-env'
ALGORITHM = 'HS256'
ACCESS_TOKEN_EXPIRE_MINUTES = 30

pwd_context = CryptContext(schemes=['bcrypt'])
oauth2_scheme = OAuth2PasswordBearer(tokenUrl='token')

def create_access_token(data: dict):
    to_encode = data.copy()
    expire = datetime.utcnow() + timedelta(minutes=ACCESS_TOKEN_EXPIRE_MINUTES)
    to_encode['exp'] = expire
    return jwt.encode(to_encode, SECRET_KEY, algorithm=ALGORITHM)

async def get_current_user(token: str = Depends(oauth2_scheme)):
    credentials_exception = HTTPException(
        status_code=status.HTTP_401_UNAUTHORIZED,
        headers={'WWW-Authenticate': 'Bearer'},
    )
    try:
        payload = jwt.decode(token, SECRET_KEY, algorithms=[ALGORITHM])
        username = payload.get('sub')
        if username is None:
            raise credentials_exception
    except JWTError:
        raise credentials_exception
    return username

Why

OAuth2PasswordBearer tells FastAPI where to find the token and generates the correct OpenAPI security schema. JWT expiry (exp claim) is verified by jose automatically when decoding.

Gotchas

  • Never hardcode SECRET_KEY — load from environment variable
  • HS256 tokens are only signed, not encrypted — don't put sensitive data in the payload
  • Token revocation requires a denylist (Redis) since JWTs are stateless
  • Use refresh tokens for longer sessions instead of long-lived access tokens
  • datetime.utcnow() is deprecated in Python 3.12 — use datetime.now(timezone.utc)

Context

FastAPI apps requiring user authentication with token-based auth

Revisions (0)

No revisions yet.