Module 10 · Lesson 01
Authentication, authorisation and the token that carries both
Login is a solved problem. Deciding what a logged-in user may touch is the design work.
What you will be able to do
- Choose between server sessions and signed tokens
- Explain the OAuth authorisation-code flow and why not to use implicit
- Design an authorisation model for a multi-tenant API
- Prevent the classic IDOR mistake in a design
Sessions or tokens
| Server session | Signed token (JWT) | |
|---|---|---|
| State | Stored in Redis or the database | Self-contained in the client |
| Revocation | Immediate, delete the session | Hard until expiry; needs a denylist |
| Horizontal scale | Needs a shared session store | Works with no lookup |
| Size | Small cookie | Often a few KB per request |
| Best for | Web apps with logout and admin revocation | Service-to-service, short-lived API access |
A design that says "JWT everywhere" without mentioning revocation is incomplete. Short expiry plus a refresh token, and a small denylist for high-risk events like password change, is the honest middle ground.
OAuth in one flow
Redirect
The app sends the user to the provider with a client id, scopes, redirect URI and a random state value.
Consent
The user authenticates with the provider and approves the requested scopes.
Callback
The provider returns a one-time code to the redirect URI. Verify the state to block CSRF.
Exchange
The backend swaps the code for an access token using the client secret. The token never touches the browser.
Use
Call the API with the access token; refresh it with the refresh token before expiry.
Two mistakes worth naming
The implicit flow puts tokens in the URL, where they leak through history and referrers. Skipping the state check makes the callback forgeable. Use authorization code with PKCE and validate state.
Authorisation models
- RBAC: roles map to permissions. Simple and auditable; weak when access depends on the specific record.
- ABAC: attributes — department, clearance, time — decide. Flexible but hard to reason about without a policy engine.
- ReBAC: relationships — "owner", "member of", "shared with" — decide. The right fit for documents, folders and orgs.
- Resource-level checks: every read and write verifies the caller's relationship to the row. Non-negotiable regardless of model.
GET /api/orders/{order_id}
1. authenticate(token) -> user_id
2. load order -> owner_id, tenant_id
3. authorise(user, order) -> user.tenant == order.tenant
AND (user.id == owner OR user.role == support)
4. return 404 (not 403) if the caller cannot know the order existsStep 3 is the one interviews probe. Changing order_id in a URL to another customer's id is insecure direct object reference, and it is prevented by checking ownership server-side on every request — never by trusting a client-supplied tenant id.
Access token lifetime
5-15 min
Limits the damage of theft
Refresh token
days-weeks, rotating
Revocable, stored hashed
Password hashing
argon2id / bcrypt
Never SHA-256 alone
Session store lookup
1 ms
Cheap enough to revoke properly
The line to say
"Every endpoint authenticates the token, then authorises against the loaded resource's tenant and owner. Roles grant capabilities; ownership grants access to a specific row."
Worth remembering
- Authentication answers who you are; authorisation answers what you may do. Confusing them creates the most common data leak.
- Tokens are stateless and hard to revoke; sessions are revocable and need a shared store.
- Always authorise on the resource, not only on the route — the id in the URL is attacker-controlled.
- Keep access tokens short-lived and refresh tokens rotating.
Checkpoint
Answer all 3 questions to finish the lesson.
1. A user changes the order id in a URL and sees another customer's order. What failed?
The caller was authenticated correctly but never checked against the loaded resource. This is insecure direct object reference.
2. Which is the main drawback of stateless tokens?
A self-contained token stays valid until it expires unless you maintain a denylist or use short lifetimes with refresh.
3. In the OAuth authorisation-code flow, where should the token exchange happen?
The code is exchanged server-side so the client secret and tokens never pass through the browser.