python
45 lines · 8 steps
API key authentication as a FastAPI dependency
A reusable dependency extracts, verifies, and validates an API key so route handlers receive an already-authenticated client.
Explained by
highlit
1import secrets
2
3from fastapi import Depends, FastAPI, HTTPException, Security, status
4from fastapi.security import APIKeyHeader
5
6from app.config import settings
7from app.db import Database, get_db
8from app.models import ApiClient
9
10api_key_header = APIKeyHeader(name="X-API-Key", auto_error=False)
11
12
13async def get_api_client(
14 api_key: str | None = Security(api_key_header),
15 db: Database = Depends(get_db),
16) -> ApiClient:
17 if not api_key:
18 raise HTTPException(
19 status_code=status.HTTP_401_UNAUTHORIZED,
20 detail="Missing API key",
21 headers={"WWW-Authenticate": "Header"},
22 )
23
24 client = await db.api_clients.find_by_key_prefix(api_key[:8])
25 if client is None or not secrets.compare_digest(client.api_key, api_key):
26 raise HTTPException(
27 status_code=status.HTTP_403_FORBIDDEN,
28 detail="Invalid API key",
29 )
30
31 if client.revoked_at is not None:
32 raise HTTPException(
33 status_code=status.HTTP_403_FORBIDDEN,
34 detail="API key has been revoked",
35 )
36
37 return client
38
39
40app = FastAPI()
41
42
43@app.get("/v1/usage")
44async def read_usage(client: ApiClient = Depends(get_api_client)):
45 return {"client_id": client.id, "plan": client.plan, "quota": client.quota_remaining}
01 / 01
STEP 01
‹ swipe to step through ›
Walkthrough
Space play
←→ step
click any line
Three takeaways
- 1Modeling auth as a dependency keeps route handlers focused on business logic while centralizing security checks.
- 2Use secrets.compare_digest for secret comparison to avoid leaking information through timing side channels.
- 3Distinguish 401 (no credentials) from 403 (bad or revoked credentials) so clients get accurate feedback.
Related explainers
php
<?php namespace App\Services;
How user impersonation works in Laravel
authentication
authorization
session
Intermediate
8 steps
php
class OrderReceiptController extends Controller { public function store(Request $request, Order $order) {
Handling receipt uploads in a Laravel controller
file-upload
validation
authorization
Intermediate
5 steps
python
import hashlib from collections import defaultdict from pathlib import Path
Finding duplicate files by size then hash
hashing
file-io
deduplication
Intermediate
7 steps
php
<?php final class RememberMeCookie {
Signed remember-me cookies in PHP
authentication
hmac
cookies
Intermediate
8 steps
java
@Component public class HeaderMergeFilter { private static final String PER_REQUEST_HEADERS = HeaderMergeFilter.class.getName() + ".headers";
Merging default and per-request headers in Spring
webclient
filters
http-headers
Intermediate
8 steps
python
from flask import Flask, request, g, jsonify from flask_babel import Babel, gettext as _, format_datetime from datetime import datetime
Per-request localization in Flask with Babel
i18n
content-negotiation
request-lifecycle
Intermediate
8 steps
Share this explainer
Here's the card — post it anywhere.
Made with highlit — turn any snippet into a walkthrough like this in about a minute.
Explain your code
Embed this explainer
Drop the interactive walkthrough into a blog or docs. Views never cost a credit.
<iframe src="https://highlit.co/explainers/api-key-authentication-as-a-fastapi-dependency-explained-python-ecd4/embed?autoplay=1" width="100%" height="520" loading="lazy" style="border:0"></iframe>
Autoplay is on by default — add ?autoplay=0 to start paused.