Skip to main content

Command Palette

Search for a command to run...

Authentication vs Authorisation: Two Questions, Two Checks

Updated
11 min readView as Markdown
Authentication vs Authorisation: Two Questions, Two Checks

Systems Design

# Post What it covers
00 APIs & Communication: How Services Talk to Each Other How services talk to each other shapes everything about a system. Nine concepts covering REST, WebSockets, async patterns, and API gateways. (146 chars)
01 API Design: Building Contracts That Last A great API is a contract that outlasts your code. Here are the principles that make APIs intuitive to consume, safe to evolve, and cheap to maintain. (154 chars)
02 REST APIs: Constraints That Create Benefits REST isn't just HTTP with JSON. It's an architectural style with specific constraints — and understanding them explains why REST APIs are designed the way they are. (166 chars)
03 Authentication vs Authorisation: Two Questions, Two Checks ← you are here Authentication is who you are. Authorisation is what you're allowed to do. Confusing them is one of the most common security mistakes in system design. (153 chars)
04 Session vs Token Authentication: Stateful vs Stateless Identity Session auth stores identity on the server. Token auth encodes it in the token. Here's how each works, where each breaks, and how to choose. (144 chars)
05 OAuth 2.0 & OpenID Connect: Delegated Access and Federated Identity OAuth 2.0 lets users grant apps access without sharing passwords. OpenID Connect adds identity on top. Here's how both actually work. (137 chars)
06 JWT: What's Actually Inside the Token JWTs are everywhere in modern auth — and frequently misused. Here's exactly what a JWT contains, how the signature works, and what it doesn't protect. (153 chars)
07 WebSockets: Real-Time Bidirectional Communication HTTP is request-response. WebSockets are a persistent two-way channel. Here's how they work, when to use them, and what to watch out for at scale. (151 chars)
08 Long Polling, SSE & Webhooks: The Server-Push Spectrum Three patterns for server-push communication — long polling, server-sent events, and webhooks. Here's how each works and when to reach for each. (150 chars)
09 Sync vs Async Communication: The Architectural Fork Synchronous services couple tightly. Asynchronous services decouple — but add complexity. Here's how to reason about which your system needs. (147 chars)
10 API Gateways: One Entry Point, Every Cross-Cutting Concern An API gateway centralises auth, rate limiting, routing, and observability for all your services. Here's what it does, how it works, and when you need one. (158 chars)
11 APIs & Communication: Wrap-Up A complete recap of all ten API and communication concepts — REST, auth, JWT, WebSockets, webhooks, async patterns, and API gateways — and how they connect. (161 chars)

Authentication vs Authorisation: Two Questions, Two Checks

The problem

A developer integrates your URL shortener API. They build a dashboard that fetches link analytics for any link ID the user types in. The API endpoint is authenticated — requests require a valid API key. It is not authorised — it doesn't check whether the API key belongs to the user who owns the link.

User A, knowing User B's link ID, requests analytics for User B's links. The request succeeds. User A can now enumerate all link IDs and harvest analytics data for any link on the platform.

The authentication check passed: "Is this a real API key?" Yes. The authorisation check was missing: "Does this API key belong to the owner of this link?" Nobody asked it.

This is Broken Object Level Authorisation — the number one API security vulnerability in the OWASP API Security Top 10. It appears in production systems built by experienced engineers because authentication and authorisation are treated as the same concern when they're not.


The core idea

Authentication is the process of verifying identity — establishing who is making a request. It answers: "Are you who you claim to be?"

Authorisation is the process of verifying permission — establishing what an authenticated identity is allowed to do. It answers: "Are you allowed to do what you're trying to do?"

Authentication always precedes authorisation — you can't determine what someone is allowed to do until you know who they are. But authentication succeeding does not imply authorisation succeeding. They are separate checks, applied in sequence, for different purposes.


The analogy: passport and visa

Authentication is a passport check at the border. The officer examines your passport — the photo, the biometric data, the issuing country's stamp — and determines whether it's genuine and belongs to you. The question being answered is purely one of identity: "Are you the person this document claims you are?"

Authorisation is the visa check. A separate officer — or the same officer making a separate determination — examines whether your passport, now verified as genuine, entitles you to enter this country, for how long, for what purposes. The question has shifted: "Does your verified identity have the right to do what you're trying to do?"

Your passport can be completely genuine and current while your visa application is denied. You can have a valid tourist visa and be prohibited from working. Authentication and authorisation are separate decisions, governed by separate rules, producing separate outcomes.


How authentication works

Authentication is the mechanism by which a system verifies that a request is from who it claims to be from. Common mechanisms:

Password-based: user provides a secret they know. Verified against a stored (hashed) version. The oldest and still most common mechanism for human users.

Token-based: client presents a token (API key, JWT, OAuth access token) issued by a trusted authority. The server verifies the token's validity — it was issued by the right authority, hasn't been tampered with, and hasn't expired.

Certificate-based (mTLS): the client presents a TLS certificate during the handshake. The server verifies the certificate against a trusted CA. Common for service-to-service authentication.

Multi-factor (MFA): combines two or more independent verification mechanisms — something you know (password), something you have (OTP device), something you are (biometric). Mitigates the risk of any single factor being compromised.

In all cases, authentication produces a principal — an identity the system can reason about. "This request is from user ID 4821" or "This request is from API key owned by Organisation 99."

Authentication in the URL shortener

POST /links
Authorization: Bearer eyJhbGciOiJSUzI1NiJ9...

Server checks:
1. Is the Bearer token present?         → 401 if missing
2. Is the token signature valid?        → 401 if invalid
3. Is the token unexpired?              → 401 if expired
4. Who does the token belong to?        → principal = user:4821

After authentication: the server knows the request is from user 4821. Nothing about what user 4821 is allowed to do has been determined yet.


How authorisation works

Authorisation uses the authenticated principal to determine whether the requested operation on the requested resource is permitted. It requires three inputs: who (the principal), what action (the operation), and on what (the resource).

Common authorisation models

Access Control Lists (ACL): a list of principals and their permitted operations, attached to each resource. Simple and explicit — "user:4821 can read and delete link:x7Kp2" — but doesn't scale to large numbers of users and resources.

Role-Based Access Control (RBAC): principals are assigned roles (admin, editor, viewer). Permissions are attached to roles, not principals. "Admins can delete any link. Editors can create and update their own links. Viewers can only read."

RBAC is the most widely used authorisation model for applications. It scales well — adding a new user means assigning a role, not updating every resource's ACL.

Attribute-Based Access Control (ABAC): permissions are evaluated based on attributes of the principal, the resource, and the environment. "A user can access a link if they are its owner, OR if the link is in a workspace they are a member of, OR if they have the admin role AND it is within business hours."

ABAC is the most expressive model and the most complex. It's used when RBAC's role-based granularity isn't sufficient — fine-grained permissions that depend on resource properties or contextual conditions.

Scope-based authorisation (OAuth scopes): common in API contexts. Access tokens carry scopes — explicit capabilities they grant. A token with scope links:read can read links but not create or delete them. A token with links:write can create and update. The API checks that the token's scopes include the scope required for the requested operation.

Object-level vs function-level authorisation

The OWASP API Security Top 10 distinguishes two levels of authorisation that must both be checked:

Function-level authorisation: "Is this principal allowed to perform this type of operation at all?" A viewer role should not be able to call DELETE /links/{id} regardless of which link ID is specified. Check the operation first.

Object-level authorisation: "Is this principal allowed to perform this operation on this specific resource?" A user with the editor role can delete links — but only their own. Check the resource after checking the operation.

Both checks are required. Missing either one creates vulnerabilities:

Request: DELETE /links/x7Kp2
Principal: user:4821

Check 1 — Function level:
  Does user:4821 have the delete permission? → Yes (editor role)

Check 2 — Object level:
  Does user:4821 own link:x7Kp2? → No (belongs to user:9934)
  → 403 Forbidden

The function-level check passing does not imply the object-level check passes. Every request needs both.

Authorisation in the URL shortener

DELETE /links/x7Kp2
Authorization: Bearer eyJhbGciOiJSUzI1NiJ9...

Authentication:
  Token valid, unexpired → principal = user:4821

Authorisation:
  Function level: does user:4821 have delete permission?
    → Check role: editor → Yes, editors can delete

  Object level: does user:4821 own link:x7Kp2?
    → Query: SELECT owner_id FROM links WHERE id = 'x7Kp2'
    → owner_id = 9934 ≠ 4821
    → 403 Forbidden: "You do not have permission to delete this link"

Errors and information leakage

The choice of error code for authorisation failures matters for security:

403 Forbidden — the server understood the request and the principal is authenticated, but they don't have permission. This reveals the resource exists.

404 Not Found — the resource doesn't exist from this principal's perspective. This hides whether the resource exists at all, preventing enumeration attacks.

For sensitive resources — private links, user data, draft content — returning 404 for resources a user doesn't have access to is often the better choice. An attacker probing for accessible resources gets no signal about what exists.


The tradeoffs

Centralised vs distributed authorisation. Authorisation logic can live in each service (distributed) or in a centralised policy service (centralised). Distributed is simpler initially but risks drift — different services implement the same rules differently. Centralised (using a policy engine like OPA — Open Policy Agent) keeps rules consistent but adds a network dependency to every authorisation check.

Performance of object-level checks. Object-level authorisation often requires a database query per request — "does this user own this resource?" At high throughput, these checks add latency. Caching ownership information, denormalising ownership into the JWT, or batching authorisation checks are common mitigations.

Fail open vs fail closed. When an authorisation service is unavailable, does your system default to allowing requests (fail open) or denying them (fail closed)? Failing closed is the secure default — a temporarily unavailable authorisation service should cause requests to fail, not silently grant access to everything.


The one thing to remember

Authentication answers "who are you?" Authorisation answers "what are you allowed to do?" They are separate checks, and both are required for every operation on every resource. An authenticated request that bypasses authorisation isn't a secured system — it's a system where every authenticated user can do everything. Check function-level permission first, object-level ownership second, and return the right error code for each failure.


← Previous: REST APIs — API design gives you the principles; REST gives you the architectural style that most HTTP APIs implement. The next post covers REST's constraints, what most APIs get wrong about REST, and how those constraints create real technical benefits.

→ Next: Session vs Token Authentication — authentication establishes identity; the next post covers the two dominant mechanisms for maintaining that identity across multiple requests.

Systems Design

Part 34 of 50

Understanding these system design concepts is essential for architects, developers, and engineers to create scalable, reliable, and maintainable software systems that meet the needs of businesses.

Up next

Session vs Token Authentication: Stateful vs Stateless Identity

Series: System Design · APIs & Communication — Pillar 3 of 8 This pillar: 00 — Overview · 01 — API Design · 02 — REST APIs · 03 — Authentication vs Authorisation · 04 — Session vs Token Auth · 05 — OA