Bearers
A bearer is a FastAPI dependency responsible for extracting and decoding the JWT token on every request. Choose the bearer that matches how your client sends the token.
Choosing a bearer
| Bearer | Token source | Recommended when |
|---|---|---|
TokenBearer |
Cookie → falls back to Authorization header |
Most apps: supports both browser (cookie) and API (header) clients |
CookieTokenBearer |
Cookie only | Browser-only apps with cookie-based auth |
HeaderTokenBearer |
Authorization header only |
Pure API / mobile clients |
All bearers share the same constructor signature:
bearer = missil.TokenBearer(
token_key="Authorization", # cookie name or header name
secret_key="...", # JWT signing secret
permissions_key="perms", # key in JWT payload holding the permissions dict
algorithms="HS256", # optional, defaults to HS256
)
Use the same permissions_key everywhere
The value of permissions_key must exactly match the key used when issuing
the token. If you sign tokens with {"perms": {"finances": 1}} but declare
the bearer with permissions_key="permissions", every request will fail.
See the JWT guide for the full payload structure.
Token revocation
By default, all tokens that pass signature and expiry validation are accepted.
To implement a revocation strategy (e.g. a Redis blocklist, a database table of
invalidated JTIs), subclass any bearer and override is_revoked:
import missil
from missil.types import JWTClaims
revoked_jtis: set[str] = set() # replace with your store
class RevokableBearer(missil.TokenBearer):
def is_revoked(self, decoded_token: JWTClaims) -> bool:
jti = decoded_token.get("jti")
return jti in revoked_jtis
jwt_bearer = RevokableBearer("Authorization", SECRET_KEY, "permissions")
When is_revoked returns True, the bearer raises TokenValidationException
with HTTP 403 before the permission check ever runs.
Note
is_revoked receives the decoded claims dict, so you have access to any
field in the payload (jti, sub, iat, etc.) to make the revocation
decision.
Working with JWT claims
Every bearer returns the decoded JWT payload as a JWTClaims dict. You can
access it in endpoint parameters by annotating with the claims type:
from typing import Annotated
import missil
from missil import JWTClaims
# Optional: subclass JWTClaims to add app-specific fields
class AppClaims(JWTClaims, total=False):
username: str
permissions: dict[str, int] # must match permissions_key
jwt_bearer = missil.TokenBearer("Authorization", SECRET_KEY, "permissions")
class AppAreas(missil.AreasBase):
finances: missil.Area
areas = AppAreas(jwt_bearer)
@app.get("/profile", dependencies=[areas.finances.READ])
def profile(user: Annotated[AppClaims, areas.finances.READ]) -> AppClaims:
username = user["username"] # typed as str
return user
JWTClaims is a TypedDict covering all standard RFC 7519 registered claims
(exp, iat, nbf, sub, iss, aud, jti). Subclassing it adds your
app-specific fields while keeping the object a plain dict at runtime —
no serialization overhead.
See also:
- Access Control guide — declaring areas and protecting endpoints
- Exceptions guide — handling
TokenValidationExceptionandPermissionDeniedException - API Reference → Bearers —
TokenBearer,CookieTokenBearer,HeaderTokenBearer,JWTClaims