How to Implement Authentication in FastAPI: Simple Guide
To implement authentication in
FastAPI, use the OAuth2PasswordBearer dependency with JWT tokens to securely verify users. Define token creation and verification logic, then protect routes by requiring valid tokens.Syntax
Authentication in FastAPI typically uses the OAuth2PasswordBearer class to declare a token URL. You create tokens (usually JWT) after verifying user credentials. Then, use dependencies to check tokens on protected routes.
OAuth2PasswordBearer(tokenUrl="token"): Declares the token endpoint.create_access_token(data: dict): Generates a JWT token.get_current_user(token: str = Depends(oauth2_scheme)): Extracts and verifies the user from the token.
python
from fastapi import Depends from fastapi.security import OAuth2PasswordBearer oauth2_scheme = OAuth2PasswordBearer(tokenUrl="token") # Function to create JWT token def create_access_token(data: dict): # encode data with secret key and expiry pass # Dependency to get current user def get_current_user(token: str = Depends(oauth2_scheme)): # decode token and verify user pass
Example
This example shows a simple FastAPI app with user login, token creation, and a protected route that requires authentication.
python
from fastapi import FastAPI, Depends, HTTPException, status from fastapi.security import OAuth2PasswordBearer, OAuth2PasswordRequestForm from jose import JWTError, jwt from passlib.context import CryptContext from datetime import datetime, timedelta app = FastAPI() # Secret key to encode JWT SECRET_KEY = "a_very_secret_key" ALGORITHM = "HS256" ACCESS_TOKEN_EXPIRE_MINUTES = 30 # Password hashing context pwd_context = CryptContext(schemes=["bcrypt"], deprecated="auto") # OAuth2 scheme oauth2_scheme = OAuth2PasswordBearer(tokenUrl="token") # Fake user database fake_users_db = { "alice": { "username": "alice", "full_name": "Alice Wonderland", "hashed_password": pwd_context.hash("secret"), "disabled": False, } } def verify_password(plain_password, hashed_password): return pwd_context.verify(plain_password, hashed_password) def get_user(db, username: str): if username in db: user_dict = db[username] return user_dict return None def authenticate_user(db, username: str, password: str): user = get_user(db, username) if not user: return False if not verify_password(password, user["hashed_password"]): return False return user def create_access_token(data: dict, expires_delta: timedelta | None = None): to_encode = data.copy() expire = datetime.utcnow() + (expires_delta if expires_delta else timedelta(minutes=15)) to_encode.update({"exp": expire}) encoded_jwt = jwt.encode(to_encode, SECRET_KEY, algorithm=ALGORITHM) return encoded_jwt 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 = get_user(fake_users_db, username) if user is None: raise credentials_exception return user @app.post("/token") async def login(form_data: OAuth2PasswordRequestForm = Depends()): user = authenticate_user(fake_users_db, form_data.username, form_data.password) if not user: raise HTTPException( status_code=status.HTTP_401_UNAUTHORIZED, detail="Incorrect username or password", headers={"WWW-Authenticate": "Bearer"}, ) 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"} @app.get("/users/me") async def read_users_me(current_user: dict = Depends(get_current_user)): return current_user
Output
Run the app and POST to /token with form data username=alice and password=secret to get a token. Use the token as Bearer in Authorization header to GET /users/me and receive user info.
Common Pitfalls
- Not hashing passwords before storing them, which is insecure.
- Forgetting to set token expiration, leading to tokens that never expire.
- Not validating the token properly, allowing unauthorized access.
- Using synchronous code for token verification in async routes, causing performance issues.
python
from fastapi import Depends, HTTPException from fastapi.security import OAuth2PasswordBearer # Wrong: No token URL specified # oauth2_scheme = OAuth2PasswordBearer() # Right: oauth2_scheme = OAuth2PasswordBearer(tokenUrl="token") # Wrong: Storing plain passwords # user_db = {"user": {"password": "mypassword"}} # Right: Store hashed passwords from passlib.context import CryptContext pwd_context = CryptContext(schemes=["bcrypt"], deprecated="auto") hashed = pwd_context.hash("mypassword") user_db = {"user": {"hashed_password": hashed}}
Quick Reference
Summary tips for FastAPI authentication:
- Use
OAuth2PasswordBearerwith a token URL. - Hash passwords with
passlibbefore storing. - Create JWT tokens with expiration using
python-jose. - Protect routes by requiring token dependency.
- Handle exceptions to return 401 on invalid tokens.
Key Takeaways
Use OAuth2PasswordBearer and JWT tokens to secure FastAPI routes.
Always hash user passwords before storing them.
Set token expiration to improve security.
Validate tokens properly to prevent unauthorized access.
Use async dependencies for smooth performance.