0% found this document useful (0 votes)
3 views22 pages

JWT FastAPI Authentication Guide

This document provides a comprehensive guide on implementing JSON Web Tokens (JWT) in FastAPI, highlighting its benefits such as statelessness, scalability, and performance. It covers the anatomy of JWT, authentication flow, environment setup, password hashing, token generation, and security practices. Additionally, it discusses advanced topics like refresh tokens, token revocation, CORS, and best practices for secure implementation.

Uploaded by

Jayakumar A
Copyright
© All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
3 views22 pages

JWT FastAPI Authentication Guide

This document provides a comprehensive guide on implementing JSON Web Tokens (JWT) in FastAPI, highlighting its benefits such as statelessness, scalability, and performance. It covers the anatomy of JWT, authentication flow, environment setup, password hashing, token generation, and security practices. Additionally, it discusses advanced topics like refresh tokens, token revocation, CORS, and best practices for secure implementation.

Uploaded by

Jayakumar A
Copyright
© All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd

1.

Introduction to JWT
JSON Web Token (JWT) is an open standard (RFC 7519) that defines a compact and self-
contained way for securely transmitting information between parties as a JSON object. This
information can be verified and trusted because it is digitally signed.

Why use JWT in FastAPI?

• Statelessness: No need to store sessions on the server side.


• Scalability: Perfect for microservices and distributed systems.
• Performance: Fast verification without database lookups for every request.

Key Benefit: In a FastAPI environment, JWTs allow for highly efficient horizontal
scaling as any instance of your application can verify a token without shared session
storage.

Page 2
2. Anatomy of a JWT
A JWT consists of three parts separated by dots (.).

[Link]

1. Header

Contains the type of token (JWT) and the signing algorithm being used (e.g., HS256).

2. Payload

Contains the claims. Claims are statements about an entity (typically, the user) and additional data.

{
"sub": "1234567890",
"name": "John Doe",
"admin": true,
"iat": 1516239022
}

3. Signature

To create the signature part you have to take the encoded header, the encoded payload, a secret,
and the algorithm specified in the header.

Page 3
3. Authentication Flow (Visualized)
The following sequence represents the handshake between the Client, API, and Database.

Client
Sends Credentials (Email/Password)

FastAPI Server
Validates Credentials against Database

FastAPI Server
Generates JWT with Secret Key

Client
Receives JWT & Stores in Local Storage/Cookies

Protected Request
Client sends JWT in 'Authorization' Header

Page 4
4. Environment Setup
To implement JWT in FastAPI, we need several core libraries for handling the web framework,
security, and token generation.

# Install required packages


pip install fastapi "uvicorn[standard]"
pip install "python-jose[cryptography]"
pip install "passlib[bcrypt]"
pip install python-multipart
pip install sqlalchemy

Project Structure Recommendation

app/
├── [Link] # Entry point
├── core/
│ ├── [Link] # Environment variables
│ └── [Link] # JWT & Password logic
├── models/ # Database models
├── schemas/ # Pydantic models
└── routers/ # API endpoints

Page 5
5. Core Configuration
Handling secrets and settings using Pydantic Settings is the production-standard approach.

# core/[Link]
from pydantic_settings import BaseSettings

class Settings(BaseSettings):
SECRET_KEY: str = "YOUR_SUPER_SECRET_KEY"
ALGORITHM: str = "HS256"
ACCESS_TOKEN_EXPIRE_MINUTES: int = 30

class Config:
env_file = ".env"

settings = Settings()

Security Tip: Never commit your .env file to Git. Use a strong 32-byte or 64-byte random string for
the SECRET_KEY.

Page 6
6. Password Hashing Logic
We use Passlib with the Bcrypt backend to ensure passwords are never stored in plain text.

# core/[Link]
from [Link] import CryptContext

pwd_context = CryptContext(schemes=["bcrypt"], deprecated="auto")

def verify_password(plain_password, hashed_password):


return pwd_context.verify(plain_password, hashed_password)

def get_password_hash(password):
return pwd_context.hash(password)

How it works: Salt is automatically generated and prepended to the hash by Bcrypt,
preventing rainbow table attacks.

Page 7
7. Token Generation (JWT)
This function creates the encoded string that becomes the user's passport to protected routes.

from datetime import datetime, timedelta, timezone


from jose import jwt
from .config import settings

def create_access_token(data: dict, expires_delta: timedelta = None):


to_encode = [Link]()
if expires_delta:
expire = [Link]([Link]) + expires_delta
else:
expire = [Link]([Link]) + timedelta(minutes=15)

to_encode.update({"exp": expire})
encoded_jwt = [Link](
to_encode,
settings.SECRET_KEY,
algorithm=[Link]
)
return encoded_jwt

Page 8
8. Database Layer
Using SQLAlchemy to define the User entity.

# models/[Link]
from sqlalchemy import Column, Integer, String, Boolean
from [Link] import Base

class User(Base):
__tablename__ = "users"

id = Column(Integer, primary_key=True, index=True)


email = Column(String, unique=True, index=True, nullable=False)
hashed_password = Column(String, nullable=False)
is_active = Column(Boolean, default=True)

Page 9
9. Pydantic Schemas
Schemas define the structure of data sent to and from the API.

# schemas/[Link]
from pydantic import BaseModel, EmailStr

class UserBase(BaseModel):
email: EmailStr

class UserCreate(UserBase):
password: str

class UserOut(UserBase):
id: int
is_active: bool

class Config:
from_attributes = True

class Token(BaseModel):
access_token: str
token_type: str

Page 10
10. Authentication Dependency
This is the engine that protects your routes. It extracts the token, validates it, and fetches the user.

# core/[Link]
from fastapi import Depends, HTTPException, status
from [Link] import OAuth2PasswordBearer
from jose import JWTError, jwt
from .config import settings

oauth2_scheme = OAuth2PasswordBearer(tokenUrl="token")

async def get_current_user(token: str = Depends(oauth2_scheme)):


credentials_exception = HTTPException(
status_code=status.HTTP_401_UNAUTHORIZED,
detail="Could not validate credentials",
headers={"WWW-Authenticate": "Bearer"},
)
try:
payload = [Link](token, settings.SECRET_KEY,
algorithms=[[Link]])
email: str = [Link]("sub")
if email is None:
raise credentials_exception
except JWTError:
raise credentials_exception

# Fetch user from DB here


return user

Page 11
11. Implementing Protected Routes
Once the dependency is created, protecting a route is as simple as adding a parameter.

@[Link]("/users/me", response_model=UserOut)
async def read_users_me(current_user: User = Depends(get_current_user)):
return current_user

Security Note: The Depends(get_current_user) ensures that any request to


this endpoint MUST include a valid, unexpired JWT in the header.

Page 12
12. The Login Endpoint
Handling the POST request to generate the token.

from [Link] import OAuth2PasswordRequestForm

@[Link]("/token", response_model=Token)
async def login_for_access_token(
form_data: OAuth2PasswordRequestForm = Depends()
):
user = authenticate_user(form_data.username, form_data.password)
if not user:
raise HTTPException(status_code=401, detail="Incorrect login")

access_token = create_access_token(data={"sub": [Link]})


return {"access_token": access_token, "token_type": "bearer"}

Page 13
13. Advanced: Refresh Tokens
Access tokens should be short-lived (e.g., 15 mins). Refresh tokens allow users to stay logged in
without re-entering credentials.

Feature Access Token Refresh Token

Lifespan Short (15-60 min) Long (7-30 days)

Storage Memory / JS State HttpOnly Cookie

Purpose API Authorization Getting new Access Token

Page 14
14. Refresh Token Logic

def create_refresh_token(data: dict):


expire = [Link]() + timedelta(days=7)
to_encode = [Link]()
to_encode.update({"exp": expire, "type": "refresh"})
return [Link](to_encode, settings.SECRET_KEY, algorithm=[Link])

@[Link]("/refresh")
async def refresh_token(old_token: str):
# 1. Validate old_token
# 2. Check if type is 'refresh'
# 3. Issue new access_token
return {"access_token": new_access_token}

Page 15
15. Token Revocation & Logout
Since JWTs are stateless, you cannot "delete" them. You must "blacklist" them until they expire.

Strategy: Use a fast in-memory store like Redis to store the JTI (JWT ID) of logged-
out tokens. Check this list in your get_current_user dependency.

# Pseudo-code for blacklist check


jti = [Link]("jti")
if [Link](f"blacklist:{jti}"):
raise HTTPException(status_code=401, detail="Token revoked")

Page 16
16. Model Context Protocol (MCP) in Auth
MCP is a modern standard for connecting AI models to data sources and tools. In the context of
FastAPI Auth, MCP can be used to:

• Automated Testing: Provide the AI with the context of your authentication schemas.
• Dynamic Documentation: Let AI generate client-side auth handlers based on your
FastAPI security dependencies.
• Context Sharing: Securely share session context between different AI-driven
microservices.

Page 17
17. CORS & Production Security
Cross-Origin Resource Sharing (CORS) is vital for frontend integration.

from [Link] import CORSMiddleware

app.add_middleware(
CORSMiddleware,
allow_origins=["[Link]
allow_credentials=True,
allow_methods=["*"],
allow_headers=["*"],
)

Security Checklist

• Use HTTPS only.


• Set HttpOnly and Secure flags on cookies.
• Implement Rate Limiting for login endpoints.

Page 18
18. Testing Auth with Pytest

from [Link] import TestClient


from [Link] import app

client = TestClient(app)

def test_login():
response = [Link]("/token", data={"username": "test@[Link]", "password":
"pwd"})
assert response.status_code == 200
assert "access_token" in [Link]()

def test_protected_route_without_token():
response = [Link]("/users/me")
assert response.status_code == 401

Page 19
19. Common Implementation Errors

Error Cause Resolution

Missing 'Bearer ' Ensure header is 'Authorization: Bearer


401 Unauthorized
prefix [token]'

Signature Verification
Wrong Secret Key Check SECRET_KEY env variable
Failed

422 Unprocessable Entity Wrong Data Format Check Pydantic schema validation

Page 20
20. Best Practices Summary

1. Short-lived tokens: Max 30 minutes for access tokens.


2. Encryption: Use RS256 (Asymmetric) for high-security environments.
3. Validation: Always validate the 'aud' (Audience) and 'iss' (Issuer) claims.
4. Logs: Never log the actual JWT or the Secret Key.

Page 21
21. Conclusion
Implementing JWT in FastAPI provides a robust, scalable, and professional way to handle user
identity. By combining the speed of FastAPI with the security of modern standards like Bcrypt and
OAuth2, you can build production-ready applications capable of handling thousands of concurrent
users.

Master Cheat Sheet: Software Testing & JWT

For further exploration, integrate this with automated testing pipelines and CI/CD security scanning.

Page 22

You might also like