Fix Broken User Authentication in FastAPI
FastAPI's flexibility often leads developers to 'roll their own' auth, resulting in catastrophic Broken Authentication (OWASP A01:2021). Common failures include plaintext password comparisons, predictable session tokens, and lack of credential salting. To secure a FastAPI app, you must move away from manual verification and leverage industry-standard cryptographic hashing and signed JWTs.
The Vulnerable Pattern
from fastapi import FastAPI app = FastAPI()VULNERABLE: Plaintext storage and static/predictable tokens
users_db = {‘admin’: ‘password123’}
@app.post(‘/login’) async def login(username, password): user_pass = users_db.get(username) if user_pass == password: # Timing attack vulnerable & plaintext leak return {‘token’: ‘admin-token-fixed’} # Static token is replayable forever return {‘error’: ‘Unauthorized’}
The Secure Implementation
The secure implementation mitigates authentication risks through three layers. 1. Password Hashing: Using Passlib with Bcrypt ensures passwords are never stored in plaintext and are resistant to brute-force via salting. 2. Standardized Extraction: OAuth2PasswordBearer handles the extraction of the Authorization header, preventing manual parsing errors. 3. Cryptographic Tokens: Instead of static strings, we use signed JWTs with an 'exp' (expiration) claim. This prevents replay attacks and allows the server to verify the token's integrity without a database lookup for every request. Always set the 'HttpOnly' and 'Secure' flags if passing tokens via cookies.
from fastapi import FastAPI, Depends, HTTPException, status
from fastapi.security import OAuth2PasswordBearer, OAuth2PasswordRequestForm
from passlib.context import CryptContext
from jose import jwt
from datetime import datetime, timedelta
SECURE CONFIG
SECRET_KEY = ‘USE_A_STRONG_RANDOM_HEX_STRING_HERE’
ALGORITHM = ‘HS256’
pwd_context = CryptContext(schemes=[‘bcrypt’], deprecated=‘auto’)
oauth2_scheme = OAuth2PasswordBearer(tokenUrl=‘token’)
app = FastAPI()
def verify_password(plain, hashed): return pwd_context.verify(plain, hashed)
@app.post(‘/token’)
async def login(form_data: OAuth2PasswordRequestForm = Depends()):
user = get_user_from_db(form_data.username)
if not user or not verify_password(form_data.password, user[‘hashed_password’]):
raise HTTPException(status_code=status.HTTP_401_UNAUTHORIZED, detail=‘Invalid credentials’)
# Issue short-lived JWT
access_token_expires = timedelta(minutes=15)
expire = datetime.utcnow() + access_token_expires
to_encode = {'sub': user['username'], 'exp': expire}
encoded_jwt = jwt.encode(to_encode, SECRET_KEY, algorithm=ALGORITHM)
return {'access_token': encoded_jwt, 'token_type': 'bearer'}</code></pre>
Your FastAPI API
might be exposed to Broken User Authentication
74% of FastAPI apps fail this check. Hackers use automated scanners to find this specific flaw. Check your codebase before they do.
Free Tier • No Credit Card • Instant Report
Verified by Ghost Labs Security Team
This content is continuously validated by our automated security engine and reviewed by our research team. Ghost Labs analyzes over 500+ vulnerability patterns across 40+ frameworks to provide up-to-date remediation strategies.