Signing In and Tokens
Signing in through django-allauth's API mode, and the JWTs it issues.
Signing In
allauth's API mode signs people in. The Next.js server makes these calls; the browser never sees a token.
POST /_allauth/app/v1/auth/loginRequest:
{
"email": "user@example.com",
"password": "your-password"
}Response (no two-factor authentication):
{
"status": 200,
"data": { "user": { "id": 1, "email": "user@example.com" } },
"meta": {
"is_authenticated": true,
"access_token": "eyJhbGciOiJSUzI1NiIs...",
"refresh_token": "eyJhbGciOiJSUzI1NiIs..."
}
}With two-factor authentication on, the password alone returns 401 with a pending mfa_authenticate step and a session_token. Send a code to finish signing in; see Two-Factor Authentication.
A wrong password answers 400 (email_password_mismatch). An account that hasn't been activated answers 401, with no tokens.
Tokens
| Setting | Default | Description |
|---|---|---|
HEADLESS_JWT_ALGORITHM | RS256 | Signed with the private key in DJANGO_JWT_PRIVATE_KEY |
HEADLESS_JWT_ACCESS_TOKEN_EXPIRES_IN | 15 minutes | DJANGO_JWT_ACCESS_TOKEN_SECONDS |
HEADLESS_JWT_REFRESH_TOKEN_EXPIRES_IN | 14 days | DJANGO_JWT_REFRESH_TOKEN_SECONDS |
HEADLESS_JWT_ROTATE_REFRESH_TOKEN | True | Each refresh returns a new refresh token; the one just used stops working |
HEADLESS_JWT_STATEFUL_VALIDATION_ENABLED | True | Every request checks the token's sign-in (allauth session) |
Each token belongs to a sign-in. Signing out, changing the password, or resetting it ends that sign-in's tokens straight away, not when they expire. The frontend refreshes a minute before the access token expires, so people stay signed in for as long as they keep using the app within 14 days.
Generate the signing key once per environment:
python manage.py generate_jwt_keyIt prints the key on one line, ready for DJANGO_JWT_PRIVATE_KEY. Changing the key signs everyone out. Production requires it; locally, without it, tokens are signed with SECRET_KEY.
Sessions are read on every API request, so production reads them through Redis (cached_db), and Celery Beat deletes expired ones daily.
Refresh
POST /_allauth/app/v1/tokens/refreshRequest:
{ "refresh_token": "eyJhbGciOiJSUzI1NiIs..." }Response:
{
"status": 200,
"data": {
"access_token": "eyJhbGciOiJSUzI1NiIs...",
"refresh_token": "eyJhbGciOiJSUzI1NiIs..."
}
}Store the new refresh token: the one you sent no longer works. A refresh token that's been used, or whose sign-in has ended, answers 400.
Signing Out
DELETE /_allauth/app/v1/auth/session
Authorization: Bearer <access_token>Ends the sign-in: neither its access token nor its refresh token works afterwards. allauth answers 401, meaning "no longer signed in".
Changing the Password
POST /_allauth/app/v1/account/password/change
Authorization: Bearer <access_token>{ "current_password": "old-password", "new_password": "new-password" }Every other device is signed out. The sign-in that made the change gets a new key, which also ends its own tokens, so allauth answers with a new session_token. Trade it for new tokens:
POST /auth/tokens/from-session/
X-Session-Token: <session_token>{ "access_token": "...", "refresh_token": "..." }A session that hasn't finished signing in (still waiting for a two-factor code) gets 401. The session token is as good as being signed in, so keep it on the server.
Usage
Include the access token in the Authorization header for all API requests:
curl -H "Authorization: Bearer eyJhbGciOiJSUzI1NiIs..." \
http://localhost:8000/api/workspaces/allauth's own endpoints accept the same header. Locally, its full API description is at /_allauth/openapi.html.