API Key Authentication
To secure your endpoints using a secret key, you can use the API key security schemes provided in fastapi.security. These schemes allow you to extract keys from headers, query parameters, or cookies and integrate them into your OpenAPI documentation.
Secure an Endpoint with a Header Key
The most common way to implement API key authentication is via a custom HTTP header using APIKeyHeader.
from fastapi import Depends, FastAPI, HTTPException, Security, status
from fastapi.security import APIKeyHeader
app = FastAPI()
# Define the scheme and the header name it looks for
api_key_scheme = APIKeyHeader(name="X-API-Key")
API_KEY = "secret-token-123"
def validate_api_key(key: str = Security(api_key_scheme)):
"""
The security scheme extracts the key, but you must implement
the validation logic yourself.
"""
if key != API_KEY:
raise HTTPException(
status_code=status.HTTP_401_UNAUTHORIZED,
detail="Invalid API Key",
)
return key
@app.get("/secure-data")
def get_secure_data(key: str = Depends(validate_api_key)):
return {"message": "Access granted", "key_used": key}
Key Components
APIKeyHeader: An instance of this class defines the security scheme. Thenameparameter specifies the header key (e.g.,X-API-Key).Security(): Used as a dependency to trigger the security scheme. It ensures that the key is extracted from the request before your validation logic runs.APIKeyBase.check_api_key: Internally, all API key classes inherit fromAPIKeyBase. When the dependency is called, it usescheck_api_keyto verify if a value exists. If missing andauto_errorisTrue(the default), it automatically raises a 401 error.
Use Query Parameters for API Keys
If you need to pass the API key in the URL (e.g., for simple webhooks), use APIKeyQuery.
from fastapi import FastAPI, Security
from fastapi.security import APIKeyQuery
app = FastAPI()
query_scheme = APIKeyQuery(name="api_key")
@app.get("/items")
def read_items(token: str = Security(query_scheme)):
return {"token": token}
When using APIKeyQuery, the client must provide the key in the URL: /items?api_key=your-secret-key.
Use Cookies for API Keys
For browser-based clients or session management, use APIKeyCookie.
from fastapi import FastAPI, Security
from fastapi.security import APIKeyCookie
app = FastAPI()
cookie_scheme = APIKeyCookie(name="session_id")
@app.get("/profile")
def get_profile(session: str = Security(cookie_scheme)):
return {"session_id": session}
Implement Optional Authentication
By default, API key schemes raise an error if the key is missing. To make authentication optional, set auto_error=False. This is useful when an endpoint provides extra data for authenticated users but remains accessible to guests.
from fastapi import FastAPI, Security
from fastapi.security import APIKeyHeader
app = FastAPI()
# auto_error=False prevents automatic 401 exceptions
optional_scheme = APIKeyHeader(name="X-API-Key", auto_error=False)
@app.get("/public-or-private")
def read_data(api_key: str | None = Security(optional_scheme)):
if api_key is None:
return {"mode": "guest", "data": "public content"}
return {"mode": "admin", "data": "secret content", "key": api_key}
Troubleshooting
Authentication vs. Validation
The classes APIKeyHeader, APIKeyQuery, and APIKeyCookie only handle extraction and OpenAPI documentation. They do not verify if the key is valid. You must always implement a validation dependency (as shown in the first example) to check the key against your database or environment variables.
The WWW-Authenticate Header
When a request fails authentication (key is missing and auto_error=True), FastAPI returns a 401 Unauthorized status. Per the APIKeyBase.make_not_authenticated_error method, the response will include a WWW-Authenticate: APIKey header. While APIKey is not a standard HTTP challenge type, it is used by this codebase to comply with RFC 9110 requirements for 401 responses.
OpenAPI Documentation
Using these classes automatically adds security requirements to your generated schema. In the /docs (Swagger UI), an Authorize button will appear, allowing users to input their API key, which will then be included in all subsequent test requests. The scheme_name parameter can be used during instantiation to customize how the scheme appears in the documentation.