Skip to main content

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. The name parameter 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 from APIKeyBase. When the dependency is called, it uses check_api_key to verify if a value exists. If missing and auto_error is True (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.