- Spec files
pypi-fastapi
Describes: pkg:pypi/fastapi@0.116.x
- Description
- FastAPI framework, high performance, easy to learn, fast to code, ready for production
- Author
- tessl
- Last updated
security-authentication.md docs/
1# Security & Authentication23FastAPI provides comprehensive security and authentication components that integrate seamlessly with dependency injection and automatic OpenAPI documentation generation. These components support various authentication schemes including API keys, HTTP authentication, and OAuth2.45## Capabilities67### Security Base Function89Core function for declaring security dependencies with optional scopes for fine-grained permission control.1011```python { .api }12def Security(13dependency: Callable = None,14*,15scopes: List[str] = None,16use_cache: bool = True17) -> Any:18"""19Declare security dependencies with scopes.2021Parameters:22- dependency: Security dependency callable23- scopes: List of required security scopes24- use_cache: Whether to cache dependency results2526Returns:27Security dependency with scope validation28"""29```3031### Security Scopes Class3233Class for handling and validating security scopes in authentication systems.3435```python { .api }36class SecurityScopes:37def __init__(self, scopes: List[str] = None) -> None:38"""39Security scopes container.4041Parameters:42- scopes: List of security scopes43"""44self.scopes = scopes or []45self.scope_str = " ".join(self.scopes)46```4748### API Key Authentication4950Classes for implementing API key authentication via different transport mechanisms.5152```python { .api }53class APIKeyQuery:54def __init__(55self,56*,57name: str,58scheme_name: str = None,59description: str = None,60auto_error: bool = True61) -> None:62"""63API key authentication via query parameters.6465Parameters:66- name: Query parameter name for the API key67- scheme_name: Security scheme name for OpenAPI68- description: Security scheme description69- auto_error: Automatically raise HTTPException on authentication failure70"""7172async def __call__(self, request: Request) -> str:73"""Extract and validate API key from query parameters."""7475class APIKeyHeader:76def __init__(77self,78*,79name: str,80scheme_name: str = None,81description: str = None,82auto_error: bool = True83) -> None:84"""85API key authentication via headers.8687Parameters:88- name: Header name for the API key89- scheme_name: Security scheme name for OpenAPI90- description: Security scheme description91- auto_error: Automatically raise HTTPException on authentication failure92"""9394async def __call__(self, request: Request) -> str:95"""Extract and validate API key from headers."""9697class APIKeyCookie:98def __init__(99self,100*,101name: str,102scheme_name: str = None,103description: str = None,104auto_error: bool = True105) -> None:106"""107API key authentication via cookies.108109Parameters:110- name: Cookie name for the API key111- scheme_name: Security scheme name for OpenAPI112- description: Security scheme description113- auto_error: Automatically raise HTTPException on authentication failure114"""115116async def __call__(self, request: Request) -> str:117"""Extract and validate API key from cookies."""118```119120### HTTP Authentication121122Classes for implementing standard HTTP authentication schemes.123124```python { .api }125class HTTPBasic:126def __init__(127self,128*,129scheme_name: str = None,130realm: str = None,131description: str = None,132auto_error: bool = True133) -> None:134"""135HTTP Basic authentication.136137Parameters:138- scheme_name: Security scheme name for OpenAPI139- realm: Authentication realm140- description: Security scheme description141- auto_error: Automatically raise HTTPException on authentication failure142"""143144async def __call__(self, request: Request) -> HTTPBasicCredentials:145"""Extract and validate Basic authentication credentials."""146147class HTTPBasicCredentials:148def __init__(self, username: str, password: str) -> None:149"""150HTTP Basic authentication credentials.151152Parameters:153- username: Username from Basic auth154- password: Password from Basic auth155"""156self.username = username157self.password = password158159class HTTPBearer:160def __init__(161self,162*,163bearerFormat: str = None,164scheme_name: str = None,165description: str = None,166auto_error: bool = True167) -> None:168"""169HTTP Bearer token authentication.170171Parameters:172- bearerFormat: Bearer token format (e.g., "JWT")173- scheme_name: Security scheme name for OpenAPI174- description: Security scheme description175- auto_error: Automatically raise HTTPException on authentication failure176"""177178async def __call__(self, request: Request) -> HTTPAuthorizationCredentials:179"""Extract and validate Bearer token credentials."""180181class HTTPAuthorizationCredentials:182def __init__(self, scheme: str, credentials: str) -> None:183"""184HTTP authorization credentials.185186Parameters:187- scheme: Authorization scheme (e.g., "Bearer")188- credentials: Authorization credentials (e.g., token)189"""190self.scheme = scheme191self.credentials = credentials192193class HTTPDigest:194def __init__(195self,196*,197scheme_name: str = None,198realm: str = None,199description: str = None,200auto_error: bool = True201) -> None:202"""203HTTP Digest authentication.204205Parameters:206- scheme_name: Security scheme name for OpenAPI207- realm: Authentication realm208- description: Security scheme description209- auto_error: Automatically raise HTTPException on authentication failure210"""211212async def __call__(self, request: Request) -> HTTPAuthorizationCredentials:213"""Extract and validate Digest authentication credentials."""214```215216### OAuth2 Authentication217218Classes for implementing OAuth2 authentication flows.219220```python { .api }221class OAuth2:222def __init__(223self,224*,225flows: Dict[str, Dict[str, Any]] = None,226scheme_name: str = None,227description: str = None,228auto_error: bool = True229) -> None:230"""231OAuth2 authentication base class.232233Parameters:234- flows: OAuth2 flows configuration235- scheme_name: Security scheme name for OpenAPI236- description: Security scheme description237- auto_error: Automatically raise HTTPException on authentication failure238"""239240class OAuth2PasswordBearer:241def __init__(242self,243tokenUrl: str,244*,245scheme_name: str = None,246scopes: Dict[str, str] = None,247description: str = None,248auto_error: bool = True249) -> None:250"""251OAuth2 password bearer authentication.252253Parameters:254- tokenUrl: URL for token endpoint255- scheme_name: Security scheme name for OpenAPI256- scopes: Available OAuth2 scopes257- description: Security scheme description258- auto_error: Automatically raise HTTPException on authentication failure259"""260261async def __call__(self, request: Request) -> str:262"""Extract and validate OAuth2 bearer token."""263264class OAuth2AuthorizationCodeBearer:265def __init__(266self,267authorizationUrl: str,268tokenUrl: str,269*,270refreshUrl: str = None,271scheme_name: str = None,272scopes: Dict[str, str] = None,273description: str = None,274auto_error: bool = True275) -> None:276"""277OAuth2 authorization code bearer authentication.278279Parameters:280- authorizationUrl: URL for authorization endpoint281- tokenUrl: URL for token endpoint282- refreshUrl: URL for token refresh endpoint283- scheme_name: Security scheme name for OpenAPI284- scopes: Available OAuth2 scopes285- description: Security scheme description286- auto_error: Automatically raise HTTPException on authentication failure287"""288289async def __call__(self, request: Request) -> str:290"""Extract and validate OAuth2 authorization code bearer token."""291292class OAuth2PasswordRequestForm:293def __init__(294self,295*,296grant_type: str = Form(regex="password"),297username: str = Form(),298password: str = Form(),299scope: str = Form(""),300client_id: str = Form(None),301client_secret: str = Form(None)302) -> None:303"""304OAuth2 password request form.305306Parameters:307- grant_type: OAuth2 grant type (must be "password")308- username: User username309- password: User password310- scope: Requested scopes311- client_id: OAuth2 client ID312- client_secret: OAuth2 client secret313"""314315class OAuth2PasswordRequestFormStrict:316def __init__(317self,318*,319grant_type: str = Form(regex="password"),320username: str = Form(),321password: str = Form(),322scope: str = Form(""),323client_id: str = Form(),324client_secret: str = Form()325) -> None:326"""327Strict OAuth2 password request form with required client credentials.328329Parameters:330- grant_type: OAuth2 grant type (must be "password")331- username: User username332- password: User password333- scope: Requested scopes334- client_id: OAuth2 client ID (required)335- client_secret: OAuth2 client secret (required)336"""337```338339### OpenID Connect Authentication340341Class for implementing OpenID Connect authentication.342343```python { .api }344class OpenIdConnect:345def __init__(346self,347*,348openIdConnectUrl: str,349scheme_name: str = None,350description: str = None,351auto_error: bool = True352) -> None:353"""354OpenID Connect authentication.355356Parameters:357- openIdConnectUrl: OpenID Connect discovery URL358- scheme_name: Security scheme name for OpenAPI359- description: Security scheme description360- auto_error: Automatically raise HTTPException on authentication failure361"""362363async def __call__(self, request: Request) -> str:364"""Extract and validate OpenID Connect token."""365```366367## Usage Examples368369### API Key Authentication370371```python372from fastapi import FastAPI, Depends, HTTPException, status373from fastapi.security import APIKeyHeader374375app = FastAPI()376377API_KEY = "your-secret-api-key"378api_key_header = APIKeyHeader(name="X-API-Key")379380def verify_api_key(api_key: str = Depends(api_key_header)):381if api_key != API_KEY:382raise HTTPException(383status_code=status.HTTP_401_UNAUTHORIZED,384detail="Invalid API Key"385)386return api_key387388@app.get("/protected")389def protected_route(api_key: str = Depends(verify_api_key)):390return {"message": "This is a protected route", "api_key": api_key}391```392393### HTTP Basic Authentication394395```python396import secrets397from fastapi import FastAPI, Depends, HTTPException, status398from fastapi.security import HTTPBasic, HTTPBasicCredentials399400app = FastAPI()401402security = HTTPBasic()403404def get_current_username(credentials: HTTPBasicCredentials = Depends(security)):405current_username_bytes = credentials.username.encode("utf8")406correct_username_bytes = b"testuser"407is_correct_username = secrets.compare_digest(408current_username_bytes, correct_username_bytes409)410current_password_bytes = credentials.password.encode("utf8")411correct_password_bytes = b"testpass"412is_correct_password = secrets.compare_digest(413current_password_bytes, correct_password_bytes414)415if not (is_correct_username and is_correct_password):416raise HTTPException(417status_code=status.HTTP_401_UNAUTHORIZED,418detail="Incorrect username or password",419headers={"WWW-Authenticate": "Basic"},420)421return credentials.username422423@app.get("/users/me")424def read_current_user(username: str = Depends(get_current_username)):425return {"username": username}426```427428### HTTP Bearer Token Authentication429430```python431from fastapi import FastAPI, Depends, HTTPException, status432from fastapi.security import HTTPBearer, HTTPAuthorizationCredentials433434app = FastAPI()435436security = HTTPBearer()437438def verify_token(credentials: HTTPAuthorizationCredentials = Depends(security)):439token = credentials.credentials440if token != "valid-bearer-token":441raise HTTPException(442status_code=status.HTTP_401_UNAUTHORIZED,443detail="Invalid authentication token"444)445return token446447@app.get("/protected")448def protected_route(token: str = Depends(verify_token)):449return {"message": "Access granted", "token": token}450```451452### OAuth2 Password Bearer Authentication453454```python455from datetime import datetime, timedelta456from jose import JWTError, jwt457from passlib.context import CryptContext458from fastapi import FastAPI, Depends, HTTPException, status459from fastapi.security import OAuth2PasswordBearer, OAuth2PasswordRequestForm460461app = FastAPI()462463SECRET_KEY = "your-secret-key"464ALGORITHM = "HS256"465ACCESS_TOKEN_EXPIRE_MINUTES = 30466467pwd_context = CryptContext(schemes=["bcrypt"], deprecated="auto")468oauth2_scheme = OAuth2PasswordBearer(tokenUrl="token")469470fake_users_db = {471"testuser": {472"username": "testuser",473"hashed_password": "$2b$12$EixZaYVK1fsbw1ZfbX3OXePaWxn96p36WQoeG6Lruj3vjPGga31lW",474"email": "test@example.com",475}476}477478def verify_password(plain_password, hashed_password):479return pwd_context.verify(plain_password, hashed_password)480481def get_password_hash(password):482return pwd_context.hash(password)483484def get_user(db, username: str):485if username in db:486user_dict = db[username]487return user_dict488489def authenticate_user(fake_db, username: str, password: str):490user = get_user(fake_db, username)491if not user:492return False493if not verify_password(password, user["hashed_password"]):494return False495return user496497def create_access_token(data: dict, expires_delta: timedelta = None):498to_encode = data.copy()499if expires_delta:500expire = datetime.utcnow() + expires_delta501else:502expire = datetime.utcnow() + timedelta(minutes=15)503to_encode.update({"exp": expire})504encoded_jwt = jwt.encode(to_encode, SECRET_KEY, algorithm=ALGORITHM)505return encoded_jwt506507async def get_current_user(token: str = Depends(oauth2_scheme)):508credentials_exception = HTTPException(509status_code=status.HTTP_401_UNAUTHORIZED,510detail="Could not validate credentials",511headers={"WWW-Authenticate": "Bearer"},512)513try:514payload = jwt.decode(token, SECRET_KEY, algorithms=[ALGORITHM])515username: str = payload.get("sub")516if username is None:517raise credentials_exception518except JWTError:519raise credentials_exception520user = get_user(fake_users_db, username=username)521if user is None:522raise credentials_exception523return user524525@app.post("/token")526async def login_for_access_token(form_data: OAuth2PasswordRequestForm = Depends()):527user = authenticate_user(fake_users_db, form_data.username, form_data.password)528if not user:529raise HTTPException(530status_code=status.HTTP_401_UNAUTHORIZED,531detail="Incorrect username or password",532headers={"WWW-Authenticate": "Bearer"},533)534access_token_expires = timedelta(minutes=ACCESS_TOKEN_EXPIRE_MINUTES)535access_token = create_access_token(536data={"sub": user["username"]}, expires_delta=access_token_expires537)538return {"access_token": access_token, "token_type": "bearer"}539540@app.get("/users/me")541async def read_users_me(current_user: dict = Depends(get_current_user)):542return current_user543```544545### Security with Scopes546547```python548from fastapi import FastAPI, Depends, HTTPException, status549from fastapi.security import OAuth2PasswordBearer, OAuth2PasswordRequestForm, SecurityScopes550551app = FastAPI()552553oauth2_scheme = OAuth2PasswordBearer(554tokenUrl="token",555scopes={556"read": "Read access",557"write": "Write access",558"admin": "Admin access"559}560)561562def get_current_user(563security_scopes: SecurityScopes,564token: str = Depends(oauth2_scheme)565):566if security_scopes.scopes:567authenticate_value = f'Bearer scope="{security_scopes.scope_str}"'568else:569authenticate_value = "Bearer"570571credentials_exception = HTTPException(572status_code=status.HTTP_401_UNAUTHORIZED,573detail="Could not validate credentials",574headers={"WWW-Authenticate": authenticate_value},575)576577# Token validation logic here578# For demo purposes, assume token is valid and contains scopes579token_scopes = ["read", "write"] # Scopes from decoded token580581for scope in security_scopes.scopes:582if scope not in token_scopes:583raise HTTPException(584status_code=status.HTTP_401_UNAUTHORIZED,585detail="Not enough permissions",586headers={"WWW-Authenticate": authenticate_value},587)588589return {"username": "testuser", "scopes": token_scopes}590591@app.get("/read-data")592async def read_data(593current_user: dict = Security(get_current_user, scopes=["read"])594):595return {"data": "This requires read access"}596597@app.post("/write-data")598async def write_data(599current_user: dict = Security(get_current_user, scopes=["write"])600):601return {"message": "Data written successfully"}602603@app.delete("/admin-action")604async def admin_action(605current_user: dict = Security(get_current_user, scopes=["admin"])606):607return {"message": "Admin action performed"}608```609610### Multiple Authentication Methods611612```python613from fastapi import FastAPI, Depends, HTTPException, status614from fastapi.security import HTTPBearer, APIKeyHeader615from typing import Union616617app = FastAPI()618619bearer_scheme = HTTPBearer(auto_error=False)620api_key_scheme = APIKeyHeader(name="X-API-Key", auto_error=False)621622async def get_current_user(623bearer_token: str = Depends(bearer_scheme),624api_key: str = Depends(api_key_scheme)625) -> dict:626# Try bearer token first627if bearer_token:628if bearer_token.credentials == "valid-bearer-token":629return {"username": "bearer_user", "auth_method": "bearer"}630631# Try API key second632if api_key:633if api_key == "valid-api-key":634return {"username": "api_user", "auth_method": "api_key"}635636# Neither authentication method worked637raise HTTPException(638status_code=status.HTTP_401_UNAUTHORIZED,639detail="Invalid authentication credentials"640)641642@app.get("/protected")643async def protected_route(current_user: dict = Depends(get_current_user)):644return {645"message": f"Hello {current_user['username']}",646"auth_method": current_user["auth_method"]647}648```649650### Custom Security Dependency651652```python653from fastapi import FastAPI, Request, HTTPException, Depends, status654655app = FastAPI()656657class CustomAuth:658def __init__(self, required_role: str = None):659self.required_role = required_role660661async def __call__(self, request: Request):662# Custom authentication logic663auth_header = request.headers.get("Authorization")664if not auth_header:665raise HTTPException(666status_code=status.HTTP_401_UNAUTHORIZED,667detail="Authorization header required"668)669670# Validate custom token format671if not auth_header.startswith("Custom "):672raise HTTPException(673status_code=status.HTTP_401_UNAUTHORIZED,674detail="Invalid token format"675)676677token = auth_header.replace("Custom ", "")678679# Mock user validation680if token == "valid-custom-token":681user = {"username": "custom_user", "role": "admin"}682else:683raise HTTPException(684status_code=status.HTTP_401_UNAUTHORIZED,685detail="Invalid token"686)687688# Check role if required689if self.required_role and user.get("role") != self.required_role:690raise HTTPException(691status_code=status.HTTP_403_FORBIDDEN,692detail="Insufficient permissions"693)694695return user696697# Use custom security698auth = CustomAuth()699admin_auth = CustomAuth(required_role="admin")700701@app.get("/user-info")702async def get_user_info(user: dict = Depends(auth)):703return user704705@app.get("/admin-only")706async def admin_only(user: dict = Depends(admin_auth)):707return {"message": "Admin access granted", "user": user}708```