1.SessionAuthentication, TokenAuthentication, and JWT
An authentication class answers one question: who sent this request? SessionAuthentication reads Django's own session cookie, so it works for a browser front-end already logged in through the normal Django login page — and because it rides on a cookie, DRF still enforces CSRF on unsafe methods. TokenAuthentication reads an `Authorization: Token <key>` header and looks that key up in a database table, which suits a mobile app or a script that has no cookie jar. A JWT is a token whose contents are signed rather than stored: the server can check it with a signing key alone, so no database row is read per request — but nothing revokes it before it expires, which is why Simple JWT issues a short-lived access token alongside a longer-lived refresh token.
Key features
- DRF's out-of-the-box `DEFAULT_AUTHENTICATION_CLASSES` is `SessionAuthentication` + `BasicAuthentication`; a real API almost always replaces it, globally in `REST_FRAMEWORK` or per-view with `authentication_classes`
- SessionAuthentication enforces CSRF for `POST`/`PUT`/`PATCH`/`DELETE` — DRF only requires the CSRF token on *authenticated* requests, unlike plain Django which requires it on anonymous POSTs too
- TokenAuthentication needs `rest_framework.authtoken` in `INSTALLED_APPS` and a migration; the header is literally `Authorization: Token <key>`, with the word `Token` and a space
- A JWT is three base64url segments — header, payload, signature — joined by dots; the payload is *signed, not encrypted*, so anyone holding the token can read the claims inside it
- Simple JWT (`djangorestframework-simplejwt`) ships `JWTAuthentication` plus `/token/` and `/token/refresh/` views, and reads the `Authorization: Bearer <token>` header, not `Token`
- A JWT cannot be revoked by deleting a row — it stays valid until `exp`; Simple JWT's optional blacklist app makes *refresh* tokens revocable, which is why access-token lifetimes are kept to minutes
Choosing a scheme
- Incoming request
- Session — state on the server, pointer in a cookie
- Cookie holds a session key — the browser attaches it automatically
- Row in django_session — one SELECT per request
- CSRF token required — unsafe methods only, authenticated requests only
- Revoke = delete the row — takes effect on the next request
- DRF Token — state on the server, key in a header
- Authorization: Token <key> — sent deliberately, never automatically
- Row in authtoken_token — one SELECT per request
- No CSRF exposure — a cross-site form cannot set a header
- No expiry built in — you add rotation yourself
- JWT — state inside the token itself
- Authorization: Bearer <jwt> — header.payload.signature
- Signature check only — zero database reads
- Payload is readable — signed, not encrypted — never put secrets in it
- Valid until exp — a deleted account still authenticates until then
Command
class OrderViewSet(viewsets.ModelViewSet):
authentication_classes = [JWTAuthentication, SessionAuthentication]
permission_classes = [IsAuthenticated]Session = server-side state behind an automatic cookie, so CSRF applies. Token = server-side state behind a deliberate header, so CSRF does not, but every request costs a database read. JWT = the state is in the signed token, so no database read at all — and no revocation before `exp`, which is why access tokens live for minutes and a refresh token does the long-lived work. A JWT payload is signed, not encrypted: never put anything secret in it.