Authentication and Authorization

Authentication and authorization are two separate checks a system makes before it acts on a request. Authentication answers "who are you?" by verifying a claimed identity, for example a password and a one-time code at sign-in. Authorization answers "what may you do?": may this identity perform this action on this resource? When Sara signs in to an expense app, authentication proves she is Sara; authorization lets her open her own claims, but not a colleague's, and not the approval that belongs to her manager.

Authentication usually happens once, at sign-in, and leaves a proof, such as the session cookie from the lesson on cookies and sessions or a token, that travels with every later request; on each request the server checks that the proof is still valid. Authorization runs again on each of those requests.

Why it matters

Access-control defects are among the most serious a tester finds. OWASP Top 10:2025 ranks Broken Access Control first (A01), and the OWASP API Security Top 10 (2023) opens with Broken Object Level Authorization (API1): change an id in a request and you receive someone else's data. Real users follow the screens built for their role, so only a test that deliberately asks for what the current user should not get finds these defects.

Telling the two checks apart also speeds up triage: a 401 and a 403 point to different code and different fixes.

Two checks, always in this order

Authentication comes first: the user, or a calling program, presents credentials and the server verifies them. There are three kinds of factor: something you know (a password), something you have (a phone that receives a one-time code, a security key) and something you are (a fingerprint). Multi-factor authentication (MFA) combines at least two different kinds; a password plus a security question is still one kind. The result is an identity the server trusts, held in a session or a token.

Authorization comes second and works on that identity. The server compares who is asking, which action and which resource with a policy: a role ("managers approve claims"), ownership ("employees read only their own claims") or attributes such as team or account status. Even a public page passes through authorization; its policy simply allows anonymous visitors.

  • Deny by default: whatever the policy does not explicitly allow is refused.
  • Least privilege: each role gets only the permissions its work needs.
  • Check every request, on the server. Hiding a button is not access control: anyone can send the request without the screen.
Authentication checks who is asking and refuses with 401; authorization then checks, on every request, whether that identity may perform this action on this resource and refuses with 403.

AuthenticationFirst check

Who is making this request?

  1. 1Credentials presentedPassword, one-time code, security key
  2. 2Server verifies them
  3. 3Identity establishedKept in a session cookie or a token
When it runs:
At sign-in; each later request carries a proof the server re-checks
Based on:
Factors: something you know, have or are; MFA combines two kinds
When it says no:
401 Unauthorized with a WWW-Authenticate challenge
Typical defect:
A request without a valid credential is served
Test by:
Sending no, wrong, expired and revoked credentials

AuthorizationSecond check

May this identity do this action on this resource?

  1. 1Request arrives with the identity
  2. 2Policy checkedRole, ownership, other attributes
  3. 3Allowed or refusedDeny by default
When it runs:
On every request, on the server
Based on:
A policy with least privilege for each role
When it says no:
403 Forbidden, or 404 if the contract hides the resource
Typical defect:
A user reads or changes another user’s data by changing an id
Test by:
Sending the same request as different users and roles

Hiding a button is not authorization: the server must refuse the request itself.

401 or 403: which check said no

RFC 9110 gives each check its own status code. 401 Unauthorized means the request lacks valid authentication credentials: none were sent, or they are wrong, expired or revoked. The server MUST send a WWW-Authenticate header with at least one challenge that says how to authenticate. Despite its name, 401 is about authentication, and the request header that carries credentials is, just as confusingly, called Authorization.

403 Forbidden means the server understood the request and refuses it. If credentials were sent, the server considers them insufficient, so repeating the request with the same ones will not help. RFC 9110 also lets a server answer 404 Not Found instead, to avoid revealing that a resource exists; if the contract chooses this, a hidden resource and a missing one must get the same answer, or the difference reveals which ids exist.

# 1. No credentials: authentication fails
GET /api/claims/5531 HTTP/1.1
Host: api.expenses.test

HTTP/1.1 401 Unauthorized
WWW-Authenticate: Bearer realm="expenses"

# 2. Omar's valid token, but claim 5531 is Sara's: authorization fails
GET /api/claims/5531 HTTP/1.1
Host: api.expenses.test
Authorization: Bearer <valid token of Omar>

HTTP/1.1 403 Forbidden

Try it: HTTP Status Code Lookup Try it: HTTP Headers Parser

Common schemes at a glance

A scheme is the way a credential or proof of identity travels with a request. The API testing module covers each one in depth; whatever the scheme, the two questions stay the same: is the proof valid (otherwise 401), and may this identity do this (otherwise 403)?

  • Session cookie: after a login form the server keeps the session and sends its id in a cookie, which the browser returns with every request.
  • Basic authentication (RFC 7617): user-id and password, joined by a colon and Base64-encoded, in the Authorization header of every request. Base64 is not encryption, so Basic is acceptable only over HTTPS.
  • Bearer token (RFC 6750): a token obtained once, for example at login, and sent as Authorization: Bearer plus the token; whoever holds it can use it until it expires or is revoked. Many are JSON Web Tokens (JWT, RFC 7519), whose readable claims name the user and often their roles or scopes.
  • API key: a long random string that identifies a calling application, not a person, sent in a header the API defines. No single standard describes it.
  • OAuth 2.0 (RFC 6749) and OpenID Connect: OAuth 2.0 is an authorization framework that gives an application an access token with limited permissions (scopes) without showing it the user's password. OpenID Connect adds an identity layer on top; "Sign in with…" buttons usually rely on it.

Try it: JWT Decoder Try it: Base64 Decoder

Worked example: who may read and approve a claim

Requirement: "Employees submit expense claims and view only their own. Managers view and approve their team's claims, but never their own. The API returns 401 without a valid token and 403 when the user may not perform the action." Test users: Sara (employee, owns claim 5531), Omar (employee, another team) and Lina (Sara's manager, owns claim 5540).

Rows 1 and 2 test authentication; rows 3 to 8 test authorization. Row 4, the classic object-level test, is row 3 with another user's token: the role may read claims, but not this one. Row 6 is a function-level test: employees may not approve any claim at all (OWASP API5:2023, Broken Function Level Authorization). After each refused write, confirm that nothing changed: claim 5531 is still "submitted" after row 6, and claim 5540 is not approved after row 7.

#  Caller               Request                        Expected  What it checks
1  no token             GET  /api/claims/5531          401       authentication
2  Sara, expired token  GET  /api/claims/5531          401       authentication
3  Sara                 GET  /api/claims/5531          200       owner may read
4  Omar                 GET  /api/claims/5531          403       not the owner
5  Lina                 GET  /api/claims/5531          200       manager of the team
6  Sara                 POST /api/claims/5531/approve  403       employees cannot approve
7  Lina                 POST /api/claims/5540/approve  403       never your own claim
8  Lina                 POST /api/claims/5531/approve  200       manager approves

Try it: API Authentication Tester

Common mistakes

  • Testing each role only through its own screens, never sending requests the screens do not offer, such as Omar asking for Sara's claim.
  • Accepting any 4xx: a missing token needs 401 with WWW-Authenticate, a forbidden action 403 (or 404 if the contract hides resources), and a refused write must leave the data unchanged.
  • Checking that a button is hidden or disabled, but never sending the request behind it.
  • Testing with one admin account, which passes every authorization check and so tests none.
  • Forgetting that rights change: a user removed from a team or deactivated may still hold an open session.

The QA perspective

Ask the authorization questions during refinement: which roles exist, who owns each kind of record, what each role may do and which status a refusal returns. Many teams keep the answers in a permission matrix (roles in rows, actions in columns, allow or deny in each cell), and every cell becomes a positive or negative test case. Agree early on test accounts for every role, including a user from another team: authorization tests always need at least two users.

In a bug report, name the check and both identities: "Omar (employee, team B) receives 200 and Sara's claim for GET /api/claims/5531; expected 403." Mask tokens and passwords. Access-control defects are often given critical or major severity, because they expose or change data the user should not reach. Test only systems you own or have written permission to test, using test accounts, never real users' credentials.

Practice exercise

Classify and predict: a clinic booking portal

Your task

A clinic portal has three roles: patients view only their own appointments; receptionists view and reschedule all appointments of their clinic; doctors view the appointments booked with them and add notes. The API returns 401 without a valid session and 403 when the user may not perform the action.

Predict the status code of each request below and say whether authentication or authorization decides it. Then add two test cases the list is missing.

Material
Setup: appointment 812 = patient Huda, Dr. Faris, North clinic
       Noor = receptionist, North clinic; Rami = receptionist, South clinic
       Ali = another patient

#  Caller                  Request
1  no session              GET   /api/appointments/812
2  Huda                    GET   /api/appointments/812
3  Huda, session expired   GET   /api/appointments/812
4  Ali                     GET   /api/appointments/812
5  Noor                    PATCH /api/appointments/812        (new time)
6  Rami                    PATCH /api/appointments/812        (new time)
7  Dr. Faris               POST  /api/appointments/812/notes
8  Huda                    POST  /api/appointments/812/notes
Steps
  1. Read the setup: who is the patient of appointment 812, and which doctor and clinic is it with?
  2. For each row, ask first whether the caller is authenticated, then whether the policy allows this action on this resource.
  3. Add two cases for roles, actions or states the list misses.
Show the model answer
Model answer

Rows 1 and 3: 401, authentication (no credentials; an expired session). RFC 9110 requires WWW-Authenticate on every 401; if it is missing, raise it as a deviation for the team to decide on.

Row 2: 200, authorization allows it: Huda is the patient. Row 4: 403, authorization at object level: Ali is authenticated but is not the patient of appointment 812.

Row 5: 2xx (usually 200, or 204 if the response has no body), authorization allows it: Noor works at the same clinic. Row 6: 403, authorization at object level: receptionists may reschedule, but Rami works at another clinic; confirm that the time of appointment 812 is unchanged.

Row 7: 2xx (201 Created if a note resource is created), authorization allows it: Dr. Faris is the appointment's doctor. Row 8: 403, authorization at function level: patients may not add notes at all.

Missing cases, for example: another doctor adds a note to appointment 812 → 403; a receptionist deactivated while her session is open sends a request → 401 or 403 as the contract defines; Huda requests appointment 99999, which does not exist → 404. Note that 403 for an existing appointment and 404 for a missing one tell a caller which ids exist, so ask whether the contract accepts that.

Frequently asked questions

Is OAuth 2.0 authentication or authorization?

OAuth 2.0 is an authorization framework: it gives an application an access token with limited permissions. On its own it does not tell the application who the user is. OpenID Connect adds that identity layer on top of OAuth 2.0 with an ID token, which is why "Sign in with…" features use OpenID Connect.

Why is 401 called "Unauthorized" if it is about authentication?

The name dates from early versions of HTTP, and RFC 9110 keeps it. What matters is the definition: 401 means the request lacks valid authentication credentials, and the server must send WWW-Authenticate. 403 means the server understood the request and refuses it. Go by the definition, not the name.

Should a forbidden resource return 403 or 404?

Either can be right. 403 is the plain answer. RFC 9110 lets a server answer 404 instead when it wants to hide that the resource exists, for example other customers' order ids. Test what the contract says, and check that a hidden resource and a missing one get exactly the same response.

Why does a web app show a login page instead of a 401?

A web app wants to show its own login form, so it usually redirects an anonymous visitor to the login page instead of returning 401, and shows a user without rights a friendly "no access" page. That is fine if the requirement says so. Confirm in the browser's developer tools that the response behind such a page holds no protected data.

References

  • RFC 9110: HTTP SemanticsIETF · 2022The meaning of HTTP methods, header fields, status codes and content negotiation, independent of the wire version.
  • OWASP Top 10:2025OWASP Foundation · 2025The ten most critical web application security risks, with how to test for and prevent each.
  • OWASP Cheat Sheet Series: AuthorizationOWASP FoundationAccess control done right: least privilege, deny by default, check permissions on every request, prefer attribute- or relationship-based models, and test the authorization logic.
  • OWASP API Security Top 10 (2023)OWASP Foundation · 2023The ten most common API weaknesses: broken object-level authorization, broken authentication, unrestricted resource consumption and more.

Practise with Mutqan tools

Test Bearer, Basic, API-key and custom-header authentication against an endpoint and compare authorised vs unauthorised responses.

API Testing

Parse raw HTTP request/response headers into a structured table with explanations.

Web

Decode JWT header and payload, inspect claims and check expiration — entirely in your browser.

Security

Decode Base64 or Base64url strings to text, with automatic padding repair.

Encoding

Go deeper

Your progress on this topic

Part of the QA Roadmap