Authentication and Authorization with FastAPI in Python 2026
Secure authentication and authorization are fundamental requirements for any modern web application. In 2026, FastAPI combined with OAuth2, JWT, and dependency injection provides a clean and powerful way to implement robust security.
TL;DR — Key Takeaways 2026
- Use OAuth2PasswordBearer + JWT for token-based authentication
- Leverage FastAPI's Dependency Injection for clean security logic
- Store hashed passwords using passlib + bcrypt
- Implement role-based and permission-based authorization
- Always use HTTPS and set proper token expiration
1. Modern Authentication Setup
from fastapi import Depends, HTTPException, status
from fastapi.security import OAuth2PasswordBearer, OAuth2PasswordRequestForm
from jose import JWTError, jwt
from passlib.context import CryptContext
from datetime import datetime, timedelta
pwd_context = CryptContext(schemes=["bcrypt"], deprecated="auto")
oauth2_scheme = OAuth2PasswordBearer(tokenUrl="token")
SECRET_KEY = "your-secret-key"
ALGORITHM = "HS256"
ACCESS_TOKEN_EXPIRE_MINUTES = 30
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)
def create_access_token(data: dict):
to_encode = data.copy()
expire = datetime.utcnow() + timedelta(minutes=ACCESS_TOKEN_EXPIRE_MINUTES)
to_encode.update({"exp": expire})
return jwt.encode(to_encode, SECRET_KEY, algorithm=ALGORITHM)
2. Current User Dependency
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 = await get_user(username=username)
if user is None:
raise credentials_exception
return user
3. Protected Routes
@app.post("/token")
async def login(form_data: OAuth2PasswordRequestForm = Depends()):
user = await authenticate_user(form_data.username, form_data.password)
if not user:
raise HTTPException(status_code=400, detail="Incorrect username or password")
access_token = create_access_token(data={"sub": user.username})
return {"access_token": access_token, "token_type": "bearer"}
@app.get("/users/me")
async def read_users_me(current_user = Depends(get_current_user)):
return current_user
Best Practices 2026
- Use JWT with short expiration + refresh tokens for better security
- Store only hashed passwords in the database
- Implement proper rate limiting on login endpoints
- Use dependency injection for all protected routes
- Consider OAuth2 with external providers (Google, GitHub) for user convenience
Conclusion
FastAPI makes secure authentication and authorization straightforward and elegant. By combining OAuth2PasswordBearer, JWT, Pydantic models, and dependency injection, you can build secure, scalable, and maintainable APIs with minimal boilerplate.
Next steps:
- Implement JWT-based authentication in your FastAPI projects following these patterns
- Related articles: FastAPI Project Structure Best Practices 2026 • Modern Web Development Best Practices 2026