FastAPI integration — dependency reference
This page documents the main FastAPI helpers exported by authtuna.integrations.fastapi_integration. Each entry shows the purpose, available options, and copyable examples (cookie sessions and bearer/API-key flows).
Quick import
from fastapi import FastAPI, Depends, Request
from authtuna.integrations.fastapi_integration import (
get_current_user,
get_current_user_optional,
get_user_ip,
resolve_token_method,
PermissionChecker,
RoleChecker,
)
app = FastAPI()Dependency: get_current_user(request, allow_public_key=False)
Returns the authenticated User instance. Supports two authentication methods: - COOKIE (session middleware must populate request.state.user_id) - BEARER (Authorization: Bearer <api_key>)
Options
- allow_public_key (bool, default False) — if True, publishable API keys (prefix
API_KEY_PREFIX_PUBLISHABLE) are allowed; otherwise the function rejects them with 403.
Examples
# Cookie-backed session (requires session middleware)
@app.get('/dashboard')
async def dashboard(user = Depends(get_current_user)):
return {"welcome": f"Hello {user.email}"}
# Allow publishable keys for a public endpoint (use carefully)
@app.get('/public-data')
async def public_data(user = Depends(lambda req: get_current_user(req, allow_public_key=True))):
return {"ok": True}Note: the second example shows using a small wrapper to pass the option — you can create a reusable dependency factory in your app for that pattern.
Dependency: get_current_user_optional(request)
Same behavior as get_current_user but returns None when the request is unauthenticated instead of raising an HTTP error. Useful for endpoints that accept both anonymous and authenticated visitors.
@app.get('/home')
async def home(user = Depends(get_current_user_optional)):
if user:
return {"message": f"Welcome back {user.email}"}
return {"message": "Welcome, please sign in"}Dependency: get_user_ip(request)
Returns the resolved IP address (populated by the session middleware). Use this for logging, rate limiting, or region-locking decisions.
@app.get('/whoami')
async def whoami(ip: str = Depends(get_user_ip)):
return {"ip": ip}Utility: resolve_token_method(request)
Returns the token method inferred for the request: "COOKIE", "BEARER", or None. It reads request.state.token_method if set by middleware; otherwise you can set it manually during tests.
def handler(request: Request):
method = resolve_token_method(request)
if method == 'COOKIE':
# UI session
pass
elif method == 'BEARER':
# API key
pass
else:
# unauthenticated
passPermissionChecker — options & examples
A dependency factory that enforces permission checks. It supports both COOKIE sessions and BEARER API keys and handles master keys vs scoped keys differently.
Constructor options
| Parameter | Type | Default | Description |
|---|---|---|---|
| *permissions | str... | — | Permission strings to check (e.g. 'projects.read') |
| mode | 'AND' | 'OR' | 'AND' | AND => all permissions required; OR => any one required |
| scope_prefix | Optional[str] | None | If set, used as the prefix when deriving a scope from a path parameter |
| scope_from_path | Optional[str] | None | Name of the path parameter to derive scope from (e.g. 'project_id') |
| raise_error | bool | True | When False the dependency returns None on failure instead of raising |
Examples
# Require a specific permission scoped to path param project_id
@app.get('/projects/{project_id}')
async def read_project(project_id: str, user = Depends(PermissionChecker('projects.read', scope_from_path='project_id'))):
return {"project_id": project_id}
# Require any of several permissions (OR mode)
@app.post('/projects/{project_id}/action')
async def project_action(project_id: str, user = Depends(PermissionChecker('projects.write', 'projects.admin', mode='OR', scope_from_path='project_id'))):
return {"ok": True}Behavior notes: for BEARER keys, master keys are treated like cookie sessions and evaluate the user's current roles/permissions dynamically; scoped keys are checked against the API key's granted scopes.
RoleChecker — options & examples
| Parameter | Type | Default | Description |
|---|---|---|---|
| *roles | str... | — | Role names to require (e.g. 'admin') |
| mode | 'AND' | 'OR' | 'AND' | AND => all roles required; OR => any one required |
| scope_prefix | Optional[str] | None | Same behavior as PermissionChecker |
| scope_from_path | Optional[str] | None | Derive the scope from the named path parameter |
| raise_error | bool | True | When False the dependency returns None instead of raising |
Examples
# Require admin role
@app.post('/admin/only')
async def admin_endpoint(user = Depends(RoleChecker('admin'))):
return {"ok": True}
# Require either manager OR admin (OR mode)
@app.post('/manage/{org_id}')
async def manage(org_id: str, user = Depends(RoleChecker('manager', 'admin', mode='OR', scope_from_path='org_id'))):
return {"ok": True}Testing & tips
- When unit-testing, you can set
request.state.token_method,request.state.user_id, andrequest.state.user_objectmanually to emulate middleware behavior. - If your app is API-only, you can skip middleware and rely on BEARER API keys for authentication and permission checks.
- To allow publishable keys on an endpoint (careful), call
get_current_userwithallow_public_key=Truevia a small wrapper dependency. - Use
raise_error=Falsewhen you prefer returningNoneand handling authorization failures inside the route (for custom responses).
For implementation details see authtuna/integrations/fastapi_integration.py in the source tree.