Skip to main content

API Key Authentication

When you need to secure your FastAPI application using a secret token provided by the client, you can use API key security schemes to automatically extract credentials from headers, query parameters, or cookies.

Authenticating with HTTP Headers

To require an API key in a custom HTTP header (like X-API-Key), use the APIKeyHeader class. This is the most common way to implement API key authentication in FastAPI.

from fastapi import Depends, FastAPI, Security, HTTPException
from fastapi.security import APIKeyHeader
from starlette.status import HTTP_403_FORBIDDEN
from pydantic import BaseModel

app = FastAPI()

# Define the security scheme
api_key_header = APIKeyHeader(name="X-API-Key", auto_error=True)

class User(BaseModel):
username: str

async def get_current_user(api_key_value: str = Security(api_key_header)):
# FastAPI extracts the header value. You must implement the validation logic.
if api_key_value == "secret-token-123":
return User(username="api_admin")

raise HTTPException(
status_code=HTTP_403_FORBIDDEN, detail="Could not validate credentials"
)

@app.get("/users/me")
def read_current_user(current_user: User = Depends(get_current_user)):
return current_user

How it works

  • APIKeyHeader(name="X-API-Key"): Creates a security scheme that looks for a header named X-API-Key.
  • Security(api_key_header): Declares the dependency. FastAPI will look for the header in the incoming request.
  • Extraction vs. Validation: APIKeyHeader only handles the extraction of the string from the request. You are responsible for verifying that the string matches a valid key in your database or configuration.

Authenticating with Query Parameters

If your API requires keys to be passed directly in the URL (e.g., ?api_key=mysecret), use APIKeyQuery.

from fastapi import Depends, FastAPI, Security
from fastapi.security import APIKeyQuery

app = FastAPI()

# Define the scheme for a query parameter named "api_key"
query_scheme = APIKeyQuery(name="api_key")

@app.get("/items/")
async def read_items(api_key: str = Security(query_scheme)):
return {"extracted_key": api_key}

Authenticating with Cookies

For browser-based clients or session-like behavior using API keys, use APIKeyCookie.

from fastapi import Depends, FastAPI, Security
from fastapi.security import APIKeyCookie

app = FastAPI()

# Define the scheme for a cookie named "session_id"
cookie_scheme = APIKeyCookie(name="session_id")

@app.get("/data/")
async def get_data(session_token: str = Security(cookie_scheme)):
return {"session_token": session_token}

Optional Authentication

By default, FastAPI raises a 401 Unauthorized error if the API key is missing. You can make the authentication optional by setting auto_error=False. This is useful for endpoints that provide extra data to logged-in users but remain accessible to the public.

from fastapi import Depends, FastAPI, Security
from fastapi.security import APIKeyHeader

app = FastAPI()

# Set auto_error to False to allow requests without the header
optional_api_key = APIKeyHeader(name="X-API-Key", auto_error=False)

@app.get("/public-data")
def read_data(api_key: str | None = Security(optional_api_key)):
if api_key is None:
return {"message": "Hello, anonymous user"}
return {"message": f"Hello, user with key {api_key}"}

Troubleshooting and Behavior

The WWW-Authenticate Header

When a request fails because the API key is missing (and auto_error is True), FastAPI returns a 401 Unauthorized status code. Per RFC 9110, this response must include a WWW-Authenticate header.

FastAPI's APIKeyBase (the parent class for Header, Query, and Cookie schemes) automatically includes WWW-Authenticate: APIKey in these error responses via the make_not_authenticated_error method.

OpenAPI Integration

All three classes (APIKeyQuery, APIKeyHeader, APIKeyCookie) automatically integrate with FastAPI's OpenAPI generation. When you use them:

  1. The security requirement appears in the /docs (Swagger UI).
  2. Swagger UI provides an "Authorize" button where you can enter the API key.
  3. The generated openapi.json correctly describes the location (in) and name of the key.

Key Extraction Logic

The extraction logic is implemented in the __call__ method of each class:

  • APIKeyQuery uses request.query_params.get(self.model.name)
  • APIKeyHeader uses request.headers.get(self.model.name)
  • APIKeyCookie uses request.cookies.get(self.model.name)

If the key is found, it is passed to check_api_key, which returns the string value. If not found and auto_error is True, it raises the HTTPException generated by make_not_authenticated_error.