Difficulty: Advanced
OAuth2 is an authorization framework that enables applications to obtain limited access to user accounts. FastAPI has built-in support for OAuth2, with the Password flow being the most common for first-party applications (where you control both the frontend and backend). In this flow, the user provides their username and password directly to your application, which exchanges them for an access token.
FastAPI provides OAuth2PasswordBearer, a security scheme class that tells FastAPI (and the Swagger UI) that the application uses Bearer token authentication. When you declare OAuth2PasswordBearer(tokenUrl="token"), it creates a dependency that extracts the token from the Authorization: Bearer <token> header. If the header is missing, it returns a 401 error.
The token endpoint is where users exchange credentials for tokens. It receives username and password via form data (not JSON), validates them, and returns an access token. The response format follows the OAuth2 specification: it must include access_token (the token string) and token_type (usually 'bearer').
OAuth2PasswordRequestForm is a FastAPI utility that parses the standard OAuth2 password flow form data. It expects form fields: username, password, and optionally scope, grant_type, client_id, and client_secret. Using this form class ensures your token endpoint follows the OAuth2 specification.
The complete flow works like this: the client sends a POST to /token with username and password as form data, the server validates the credentials and returns a JWT token, the client stores the token, and for subsequent requests the client includes the token in the Authorization header as 'Bearer <token>'. The server verifies the token on each request using a dependency.
The Swagger UI at /docs automatically shows a 'Authorize' button when OAuth2PasswordBearer is used. Clicking it presents a login form where you can enter credentials. After authentication, all subsequent requests from the Swagger UI include the token automatically. This makes interactive API testing seamless.
from fastapi import FastAPI, Depends, HTTPException
from fastapi.security import OAuth2PasswordBearer, OAuth2PasswordRequestForm
app = FastAPI()
# Security scheme - tells FastAPI about Bearer token auth
oauth2_scheme = OAuth2PasswordBearer(tokenUrl="token")
# Fake user database
fake_users = {
"alice": {"username": "alice", "password": "secret123", "role": "admin"},
"bob": {"username": "bob", "password": "password456", "role": "user"},
}
# Token endpoint - exchange credentials for token
@app.post("/token")
def login(form_data: OAuth2PasswordRequestForm = Depends()):
user = fake_users.get(form_data.username)
if not user or user["password"] != form_data.password:
raise HTTPException(
status_code=401,
detail="Incorrect username or password",
headers={"WWW-Authenticate": "Bearer"},
)
# In a real app, create a JWT token here
return {"access_token": form_data.username, "token_type": "bearer"}
# Protected endpoint - requires valid token
@app.get("/me")
def read_current_user(token: str = Depends(oauth2_scheme)):
# In a real app, decode the JWT token here
user = fake_users.get(token)
if not user:
raise HTTPException(status_code=401, detail="Invalid token")
return {"username": user["username"], "role": user["role"]}
OAuth2PasswordBearer creates a dependency that extracts Bearer tokens from the Authorization header. The /token endpoint validates credentials and returns a token. Protected endpoints use Depends(oauth2_scheme) to require authentication.
from fastapi import FastAPI, Depends, HTTPException
from fastapi.security import OAuth2PasswordBearer, OAuth2PasswordRequestForm
from pydantic import BaseModel
app = FastAPI()
oauth2_scheme = OAuth2PasswordBearer(tokenUrl="token")
class Token(BaseModel):
access_token: str
token_type: str
class User(BaseModel):
username: str
email: str
role: str
fake_users_db = {
"alice": {
"username": "alice",
"email": "alice@example.com",
"password": "secret",
"role": "admin",
},
}
def get_current_user(token: str = Depends(oauth2_scheme)) -> User:
user_data = fake_users_db.get(token)
if not user_data:
raise HTTPException(
status_code=401,
detail="Could not validate credentials",
headers={"WWW-Authenticate": "Bearer"},
)
return User({k: v for k, v in user_data.items() if k != "password"})
@app.post("/token", response_model=Token)
def login(form_data: OAuth2PasswordRequestForm = Depends()):
user = fake_users_db.get(form_data.username)
if not user or user["password"] != form_data.password:
raise HTTPException(status_code=401, detail="Bad credentials")
return Token(access_token=user["username"], token_type="bearer")
@app.get("/me", response_model=User)
def read_me(current_user: User = Depends(get_current_user)):
return current_user
@app.get("/admin")
def admin_only(current_user: User = Depends(get_current_user)):
if current_user.role != "admin":
raise HTTPException(status_code=403, detail="Admin only")
return {"message": f"Welcome admin {current_user.username}"}
A get_current_user dependency wraps the token extraction and user lookup. Protected endpoints depend on get_current_user to get a typed User object. Role-based authorization checks the user's role in the handler.
from fastapi import FastAPI, Depends
from fastapi.security import OAuth2PasswordBearer
app = FastAPI()
# auto_error=False makes the token optional
oauth2_scheme = OAuth2PasswordBearer(tokenUrl="token", auto_error=False)
def get_optional_user(token: str | None = Depends(oauth2_scheme)):
if token is None:
return None
# Validate token and return user
users = {"valid-token": {"name": "Alice"}}
return users.get(token)
@app.get("/content")
def get_content(user: dict | None = Depends(get_optional_user)):
if user:
return {"content": "Premium content", "user": user["name"]}
return {"content": "Public content only"}
# Without token: returns public content
# With valid token: returns premium content
Setting auto_error=False on OAuth2PasswordBearer makes the token optional. Instead of returning 401 when the token is missing, it returns None. This enables endpoints that show different content for authenticated vs anonymous users.
OAuth2, Password Flow, Token Endpoint, Bearer Token, OAuth2PasswordBearer