Security & Authentication
FastAPI provides an integrated security system built on top of its dependency injection mechanism. Instead of using complex middleware or global state, you define security requirements as dependencies that can be injected into any path operation. This approach ensures that security schemes are automatically documented in the generated OpenAPI schema and visible in the Swagger UI.
HTTP Authentication
When you need standard HTTP authentication, FastAPI provides classes in fastapi.security.http that handle the extraction and parsing of the Authorization header.
Basic Authentication
If you want to prompt the user for a username and password using the browser's built-in dialog, use the HTTPBasic class.
from typing import Annotated
from fastapi import Depends, FastAPI
from fastapi.security import HTTPBasic, HTTPBasicCredentials
app = FastAPI()
security = HTTPBasic()
@app.get("/users/me")
def read_current_user(credentials: Annotated[HTTPBasicCredentials, Depends(security)]):
return {"username": credentials.username, "password": credentials.password}
Internally, HTTPBasic (defined in fastapi/security/http.py) inherits from HTTPBase. When called, it retrieves the Authorization header, checks if the scheme is basic, and decodes the Base64-encoded credentials. It returns an HTTPBasicCredentials Pydantic model containing the username and password.
Bearer Tokens
For APIs using JWTs or opaque tokens, HTTPBearer extracts the token from the Authorization: Bearer <token> header.
from fastapi import Depends, FastAPI
from fastapi.security import HTTPBearer, HTTPAuthorizationCredentials
app = FastAPI()
security = HTTPBearer()
@app.get("/items/")
def read_items(credentials: Annotated[HTTPAuthorizationCredentials, Depends(security)]):
return {"token": credentials.credentials}
HTTPBearer returns an HTTPAuthorizationCredentials object. Note that FastAPI does not validate the token for you; it only extracts it. You must implement the validation logic (e.g., checking a database or verifying a JWT signature) in a subsequent dependency.
[!WARNING]
HTTPDigestis also available infastapi/security/http.py, but it is currently only a stub for OpenAPI documentation. It does not implement the complex challenge-response logic required for Digest authentication.
API Key Authentication
If your application uses API keys passed via headers, query parameters, or cookies, use the classes in fastapi/security/api_key.py. These classes extract the key value as a raw string.
APIKeyHeader: Extracts the key from a custom header (e.g.,X-API-Key).APIKeyQuery: Extracts the key from a URL query parameter.APIKeyCookie: Extracts the key from a browser cookie.
from fastapi import Depends, FastAPI
from fastapi.security import APIKeyHeader
app = FastAPI()
api_key_header = APIKeyHeader(name="X-API-Key")
@app.get("/secure-data")
def get_data(api_key: str = Depends(api_key_header)):
return {"key_received": api_key}
If the key is missing and auto_error is True (the default), FastAPI raises an HTTPException with a 401 status code.
OAuth2 with Password Flow
FastAPI provides comprehensive support for OAuth2, specifically the "Password Flow" which is common for first-party applications. This involves two main components: a login endpoint that issues tokens and protected endpoints that verify them.
The Login Endpoint
To handle the login request, use OAuth2PasswordRequestForm. This dependency parses the request body, which the OAuth2 specification requires to be application/x-www-form-urlencoded.
from typing import Annotated
from fastapi import Depends, FastAPI
from fastapi.security import OAuth2PasswordRequestForm
app = FastAPI()
@app.post("/token")
async def login(form_data: Annotated[OAuth2PasswordRequestForm, Depends()]):
# form_data.username and form_data.password are available here
return {"access_token": form_data.username, "token_type": "bearer"}
In fastapi/security/oauth2.py, OAuth2PasswordRequestForm defines fields for username, password, scope, client_id, and client_secret. If you need to strictly enforce the grant_type="password" field as per the spec, use OAuth2PasswordRequestFormStrict.
Protecting Routes
To protect routes, instantiate OAuth2PasswordBearer with the tokenUrl pointing to your login endpoint.
from fastapi.security import OAuth2PasswordBearer
oauth2_scheme = OAuth2PasswordBearer(tokenUrl="token")
@app.get("/users/me")
async def read_users_me(token: Annotated[str, Depends(oauth2_scheme)]):
return {"token": token}
The tokenUrl is used by Swagger UI to know where to send the credentials when you click the "Authorize" button.
Scopes and Permissions
OAuth2 scopes allow you to define fine-grained permissions. FastAPI manages these using the Security function and the SecurityScopes class.
Requiring Scopes
Use Security instead of Depends when you want to specify required scopes for a path operation.
from fastapi import Security
from fastapi.security import OAuth2PasswordBearer
oauth2_scheme = OAuth2PasswordBearer(tokenUrl="token", scopes={"items:read": "Read items"})
@app.get("/items/")
async def read_items(token: Annotated[str, Security(oauth2_scheme, scopes=["items:read"])]):
return [{"item_id": "portal-gun"}]
Accessing Scopes in Dependencies
If you have a dependency that needs to know which scopes were requested by the path operation (e.g., to verify them against a user's permissions), inject SecurityScopes.
from fastapi.security import SecurityScopes
async def get_current_user(security_scopes: SecurityScopes, token: Annotated[str, Depends(oauth2_scheme)]):
if security_scopes.scopes:
authenticate_value = f'Bearer scope="{security_scopes.scope_str}"'
else:
authenticate_value = "Bearer"
# Logic to verify token and check if user has security_scopes.scopes
...
SecurityScopes (defined in fastapi/security/oauth2.py) provides a scopes list containing all scopes required by the current dependency and any parent dependencies in the chain.
Internal Implementation: SecurityBase
All security schemes in FastAPI inherit from SecurityBase (found in fastapi/security/base.py). This base class ensures that the scheme is correctly registered in the app.openapi() dictionary.
When a security dependency is called:
- It receives the
starlette.requests.Requestobject. - It attempts to extract the credentials (header, cookie, or query).
- If credentials are missing and
auto_errorisTrue, it raises anHTTPExceptionusingmake_not_authenticated_error(). - It returns the extracted credentials to your path operation or dependency.
This architecture allows you to swap security implementations easily by changing the dependency injected into your routes.