JWT¶
FastAuth uses joserfc for JWT creation and validation. Both symmetric (HS256) and asymmetric (RS256/RS512) algorithms are supported.
HS256 (default)¶
Uses a shared HMAC secret. Simple to set up, suitable for single-service deployments.
from fastauth import FastAuthConfig
from fastauth.config import JWTConfig
config = FastAuthConfig(
secret="my-secret-key", # must be long and random
jwt=JWTConfig(algorithm="HS256"), # default
...
)
Generate a secure secret:
Warning
The secret must be at least 32 characters for HS256. Never hard-code it — use environment variables.
RS256 / RS512¶
Uses an RSA key pair. The private key signs tokens; the public key verifies them. This lets other services (microservices, CDNs) verify tokens without the private key.
Generate keys¶
Or use the helper script in the examples:
Configure¶
from pathlib import Path
config = FastAuthConfig(
secret="still-required-for-the-config",
jwt=JWTConfig(
algorithm="RS256",
private_key=Path("private.pem").read_text(),
public_key=Path("public.pem").read_text(),
),
...
)
JWKS (JSON Web Key Sets)¶
When jwks_enabled=True, FastAuth exposes a /.well-known/jwks.json endpoint that publishes the current public key(s). Other services can fetch this endpoint to verify tokens without you distributing the public key file.
config = FastAuthConfig(
secret="...",
jwt=JWTConfig(
algorithm="RS256",
jwks_enabled=True,
key_rotation_interval=86400, # rotate keys every 24 hours
),
...
)
You must also call initialize_jwks() in your lifespan handler:
@asynccontextmanager
async def lifespan(app: FastAPI):
await auth.initialize_jwks()
await adapter.create_tables()
yield
Token structure¶
A decoded FastAuth access token looks like:
{
"sub": "cuid2-user-id",
"type": "access",
"iat": 1700000000,
"exp": 1700000900,
"iss": "https://your-app.com",
"aud": ["your-app"]
}
Refresh tokens use "type": "refresh" and have a longer exp.
Custom claims¶
Use the modify_jwt hook to add custom claims:
class MyHooks(EventHooks):
async def modify_jwt(self, token: dict, user: UserData) -> dict:
token["email"] = user["email"]
token["plan"] = user.get("plan", "free")
return token
See Guides → Microservice JWT for a full RS256 + JWKS microservice example.