Last modified: Dec 01, 2025 By Alexander Williams
FastAPI JWT Authentication Python Tutorial
Security is vital for modern web APIs. FastAPI makes it simple.
This guide teaches you JWT authentication. You will secure your API endpoints.
We cover user login, token creation, and route protection. Let's begin.
Understanding JWT Authentication
JWT stands for JSON Web Token. It is a compact, URL-safe token standard.
Tokens encode user data as JSON. They are cryptographically signed.
This allows stateless authentication. The server does not store session data.
A JWT has three parts: Header, Payload, and Signature. They are dot-separated.
Project Setup and Installation
First, ensure Python is installed. Then, install the required packages.
Use pip, the Python package manager. Install FastAPI and related libraries.
If you face issues, see our guide on How to Install FastAPI in Python.
We also need PyJWT for token handling. And python-multipart for form data.
pip install fastapi uvicorn python-jose[cryptography] passlib[bcrypt] python-multipart
Creating the User Model and Database
We need a user model. It stores credentials like username and password.
For simplicity, we use a Pydantic model. In real apps, use a database.
Check our FastAPI SQLAlchemy CRUD Guide for database integration.
We also hash passwords. Never store plain text passwords.
from pydantic import BaseModel
from passlib.context import CryptContext
# Password hashing context
pwd_context = CryptContext(schemes=["bcrypt"], deprecated="auto")
class User(BaseModel):
username: str
email: str = None
hashed_password: str
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)
Implementing the Login Endpoint
Create a route for user login. It accepts username and password.
The endpoint verifies credentials. If valid, it issues a JWT token.
We use the OAuth2PasswordRequestForm for security. It handles form data.
This is a critical security step. Always validate input thoroughly.
from fastapi import FastAPI, Depends, HTTPException, status
from fastapi.security import OAuth2PasswordBearer, OAuth2PasswordRequestForm
from jose import JWTError, jwt
from datetime import datetime, timedelta
app = FastAPI()
# Secret key and algorithm
SECRET_KEY = "your-secret-key-change-this"
ALGORITHM = "HS256"
ACCESS_TOKEN_EXPIRE_MINUTES = 30
oauth2_scheme = OAuth2PasswordBearer(tokenUrl="token")
# Fake user database for demo
fake_users_db = {
"johndoe": {
"username": "johndoe",
"hashed_password": get_password_hash("secret123"),
}
}
@app.post("/token")
async def login(form_data: OAuth2PasswordRequestForm = Depends()):
user_dict = fake_users_db.get(form_data.username)
if not user_dict:
raise HTTPException(status_code=400, detail="Incorrect username")
user = User(**user_dict)
if not verify_password(form_data.password, user.hashed_password):
raise HTTPException(status_code=400, detail="Incorrect password")
# Create JWT token
access_token_expires = timedelta(minutes=ACCESS_TOKEN_EXPIRE_MINUTES)
access_token = create_access_token(
data={"sub": user.username}, expires_delta=access_token_expires
)
return {"access_token": access_token, "token_type": "bearer"}
Creating and Signing JWT Tokens
We need a function to create tokens. It uses the secret key and algorithm.
The token includes an expiration time. This limits its validity period.
We use the jwt.encode method from python-jose. It signs the token.
Always set a short expiration for security. Refresh tokens can renew access.
def create_access_token(data: dict, expires_delta: timedelta = None):
to_encode = data.copy()
if expires_delta:
expire = datetime.utcnow() + expires_delta
else:
expire = datetime.utcnow() + timedelta(minutes=15)
to_encode.update({"exp": expire})
encoded_jwt = jwt.encode(to_encode, SECRET_KEY, algorithm=ALGORITHM)
return encoded_jwt
Protecting Routes with Dependency Injection
Now, protect your API routes. Use FastAPI's dependency injection system.
Create a dependency function. It validates the incoming JWT token.
The function extracts the token from the Authorization header. It decodes and verifies it.
If the token is invalid or expired, it raises an HTTP 401 error.
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 = jwt.decode(token, SECRET_KEY, algorithms=[ALGORITHM])
username: str = payload.get("sub")
if username is None:
raise credentials_exception
except JWTError:
raise credentials_exception
user = fake_users_db.get(username)
if user is None:
raise credentials_exception
return user
@app.get("/users/me")
async def read_users_me(current_user: User = Depends(get_current_user)):
return current_user
Testing the Authentication Flow
Run your FastAPI app with Uvicorn. Test the endpoints with a tool like curl.
First, get a token from the /token endpoint. Use a POST request with credentials.
Then, use the token to access the protected /users/me route. Include it in the header.
This demonstrates the complete flow. It is the core of API security.
# Request a token
curl -X POST "http://localhost:8000/token" -H "Content-Type: application/x-www-form-urlencoded" -d "username=johndoe&password=secret123"
# Expected output
{"access_token":"eyJhbGciOiJIUzI1NiIs...","token_type":"bearer"}
# Access protected route with token
curl -X GET "http://localhost:8000/users/me" -H "Authorization: Bearer eyJhbGciOiJIUzI1NiIs..."
# Expected output
{"username":"johndoe","email":null,"hashed_password":"$2b$12$..."}
Best Practices and Security Considerations
Use environment variables for secrets. Never hardcode your SECRET_KEY.
Implement proper password hashing. We used bcrypt via Passlib.
Consider using HTTPS in production. It encrypts data in transit.
Add rate limiting to login endpoints. This prevents brute force attacks.
For more advanced features, like file handling, see our FastAPI File Upload Download Tutorial.
Conclusion
You have learned to implement JWT authentication in FastAPI. It is a powerful method.
We covered user login, token generation, and route protection. These are essential skills.
FastAPI's tools make this process clean and secure. Your APIs are now safer.
Remember to follow security best practices. Keep your secret keys safe.
For a broader introduction, start with our FastAPI Tutorial: Build Your First Python REST API.
Happy coding and building secure applications with FastAPI.