QA How-To
HTTP 401 vs 403: What Testers Need to Know
Learn HTTP status 401 vs 403 authentication and authorization semantics, headers, token tests, security edge cases, automation, and interview answers.
25 min read | 3,923 words
TL;DR
HTTP 401 means valid authentication credentials are missing or unacceptable, and the response should include an appropriate WWW-Authenticate challenge. HTTP 403 means the server refuses the request, usually because the authenticated caller lacks sufficient permission. Test credential states and permission states independently, then verify no data or side effect leaks through alternate paths.
Key Takeaways
- 401 means the request lacks valid authentication credentials for the target resource, despite the historical Unauthorized label.
- 403 means the server understood the request but refuses to fulfill it, commonly because an authenticated principal lacks permission.
- A 401 response needs a valid WWW-Authenticate challenge that matches the supported authentication scheme.
- For bearer tokens, test missing, malformed, invalid, expired, revoked, wrong-audience, wrong-issuer, and insufficient-scope cases separately.
- Authorization tests must cover role, scope, tenant, ownership, resource state, field-level rules, and every alternate endpoint for the same data.
- A server can return 404 instead of 403 to conceal that a protected resource exists, but the policy must be consistent and side-channel aware.
- Verify status, headers, safe body, unchanged state, audit event, cache policy, browser behavior, and absence of sensitive information.
The http status 401 vs 403 distinction is the boundary between proving identity and being allowed to perform an action. 401 Unauthorized means the request lacks valid authentication credentials for the target resource. 403 Forbidden means the server understood the request but refuses to fulfill it, commonly because the authenticated principal does not have sufficient permission.
The labels cause confusion because 401 is historically named Unauthorized even though authentication is the practical issue. A tester needs more than two happy assertions. Token validity, challenge headers, roles, scopes, tenants, ownership, concealment, browser redirects, caching, audit records, and side effects all influence whether the access-control contract is actually secure.
TL;DR
| Scenario | Expected direction | Main evidence |
|---|---|---|
| No credentials | 401 | WWW-Authenticate challenge, no protected data |
| Malformed or invalid token | 401 | Safe invalid-credential response |
| Expired or revoked token | 401 | Reauthentication possible, no state change |
| Valid identity, missing required permission | 403 | Stable insufficient-permission response |
| Valid token, insufficient OAuth scope | 403 | Bearer challenge can identify required scope safely |
| Cross-tenant or nonowned resource | 403 or concealment 404 policy | No existence or content leak |
| Valid permission and matching resource | Success code | Correct least-privilege access |
Do not test these cases by changing only the expected number. Create principals and tokens whose validity and permissions are independently controlled.
1. HTTP Status 401 vs 403 in Precise Terms
A 401 response says the request has not been applied because it lacks valid authentication credentials for the target resource. The response includes a WWW-Authenticate header containing at least one challenge applicable to the resource. A client can use that challenge to understand the authentication scheme and potentially obtain or refresh credentials.
A 403 response says the server understood the request but refuses to fulfill it. Credentials may be present and valid but inadequate. Repeating the same request with the same identity and permission state will not help. The principal needs a changed role, scope, ownership, approval, network context, resource state, or policy outcome. 403 can also represent a refusal where revealing the exact reason would be unsafe.
A useful mental model is identity before permission. Ask, who are you? If the server cannot establish an acceptable identity for the protected resource, expect 401. If the server knows enough to evaluate policy and says this operation is not allowed, expect 403. This model is practical, but the published scheme and security policy remain authoritative.
Authentication success does not imply authorization success. A token can have a valid signature, issuer, audience, time window, and subject while lacking orders:refund. Conversely, permission claims in an invalid token are meaningless because the credential cannot establish identity. Tests must control these dimensions separately.
Do not treat 401 and 403 as generic error codes for failed login screens. A login endpoint can return 400, 401, 429, or a deliberately uniform response according to its threat model. Evaluate the actual protected-resource protocol and consumer behavior.
2. Compare Authentication and Authorization Evidence
Authentication evidence includes a session cookie, bearer access token, mutual TLS identity, API key, signed request, or another supported credential. Authorization evidence includes role assignments, OAuth scopes, permissions, tenant membership, resource ownership, relationship rules, field policy, environmental conditions, and resource state. A test principal should have a documented combination, not a vaguely named admin token.
| Dimension | Authentication test | Authorization test |
|---|---|---|
| Primary question | Is the credential acceptable for this resource? | May this principal perform this operation here? |
| Negative fixture | Missing, malformed, expired, revoked, wrong issuer or audience | Valid token with missing role, scope, ownership, or tenant |
| Expected code | Usually 401 | Usually 403 or documented concealment 404 |
| Critical header | WWW-Authenticate | Optional scheme-specific challenge or policy metadata |
| State expectation | Request not applied | Forbidden operation not applied |
| Common false positive | Token fixture is accidentally still valid | Principal inherits access through another role or group |
Build credentials from a test identity provider or deterministic local issuer in controlled environments. Avoid hand-editing a token payload and assuming it remains valid. A signed token whose payload was changed should fail signature authentication and produce 401, not reach a permission check. To test insufficient scope, mint a valid token intentionally lacking that scope.
Record expected effective permissions for every principal. Group membership, default roles, wildcard policies, cached entitlements, and administrative bypasses can make a supposedly forbidden fixture authorized. A setup assertion can call a safe identity or entitlement endpoint and fail early if the fixture drifts.
For interview preparation on broader response behavior, API error handling and negative testing connects access control with validation and conflict precedence.
3. Validate WWW-Authenticate on 401 Responses
WWW-Authenticate is not optional decoration on a 401. It communicates one or more challenges for the target resource. A Basic challenge can include a realm. A Bearer challenge can carry standardized parameters such as realm, error, error description, error URI, or scope as defined by the bearer-token protocol. The exact challenge depends on the authentication scheme.
Parse the header according to its grammar rather than splitting blindly on commas. Multiple challenges and quoted parameter values can contain commas. In most API tests, assert the expected scheme case-insensitively and selected safe parameters. Do not require volatile wording. Confirm a gateway has not stripped the header or replaced the application's Bearer challenge with its own unrelated scheme.
A response for a missing bearer token can simply advertise Bearer and realm information. For an invalid or expired access token, the resource server can use the bearer error invalid_token and return 401. Error descriptions must not reveal signing keys, token content, internal clocks, user status, or validator stack traces. The client should know to reauthenticate or refresh, not receive a forensic report.
Test multiple supported schemes if the resource genuinely accepts them. Challenges should match what can work for that resource. A 401 that advertises Basic while only OAuth Bearer works sends clients down a dead end. If a browser page redirects unauthenticated users to login, also test the underlying API behavior. Returning HTML login content with 200 to an API fetch can break SDKs and conceal authentication failure.
CORS must expose WWW-Authenticate to browser JavaScript when the application needs to read it, subject to the architecture. Preflight behavior is separate and must not be confused with business authentication.
4. Test Bearer Token Failure States Separately
One invalid-token test does not cover authentication. Create a matrix for absent Authorization, wrong scheme, missing token value, malformed token structure, invalid signature, unknown key identifier, expired token, not-yet-valid token, revoked token where revocation applies, wrong issuer, wrong audience, wrong authorized party where used, and unacceptable token type. Each case should produce the documented 401 behavior without protected content or mutation.
Time claims need a controlled clock or tokens minted around deliberate boundaries. Test just before, at, and just after expiry according to the validator's skew policy. Do not wait in real time for long expirations. Across distributed services, inconsistent clock tolerance can make the same token alternate between success and 401. Component tests can inject time, while deployed tests compare approved instances under synchronized infrastructure.
Key rotation deserves coverage. A token signed with the active key succeeds. A token signed with a retired key follows retention policy. A newly published key becomes usable after cache refresh without a long authentication outage. Do not fetch arbitrary key URLs from untrusted token headers. The issuer configuration should control where verification keys come from.
For opaque tokens, test active and inactive introspection results, audience and scope enforcement, timeout behavior, and safe failure when the authorization server is unavailable. A dependency outage should not accidentally authorize. Whether the public response is 401 or a 5xx under that condition depends on policy, but it must not leak protected data.
Keep actual tokens out of reports. Log a safe test-case identifier and response correlation ID, never the Authorization header.
5. Test Roles, Scopes, Ownership, Tenants, and Resource State
Authorization is multidimensional. A role such as support agent might read customer profiles but not export them. An OAuth scope might allow order reads but not refunds. Ownership might let a customer view only their orders. Tenant membership must prevent identical IDs from crossing organizations. A resource state might permit cancellation before shipment but forbid it afterward. Field rules might allow editing a display name but not account status.
Build an access-control matrix with principals as rows and resource operations as columns. Include anonymous, ordinary owner, ordinary nonowner, peer in same tenant, user in another tenant, read-only operator, narrowly scoped service account, privileged operator, and disabled or removed principal where relevant. Avoid an enormous role matrix by grouping policies with identical effective permissions, then keep explicit cases for high-risk boundaries.
Positive authorization tests are necessary. If every principal receives 403, the negative suite passes while the feature is unusable. For each permission, prove the least-privileged intended principal succeeds and a nearby principal without the permission fails. Verify the action's resulting state and attribution.
Test alternate paths to the same data: item endpoint, collection filters, search, exports, reports, GraphQL fields, file URLs, batch operations, websocket topics, event subscriptions, and caches. Protecting /orders/42 while leaking it through /orders?customerId=... is an object-level authorization defect.
For systematic threat coverage, use API security testing basics. Perform access tests only with authorized tenants and synthetic data.
6. Build Runnable Python Standard-Library Tests
The following unittest module uses only Python's standard urllib client. It prevents automatic redirect behavior from obscuring auth responses, captures HTTPError as the expected response, and tests a protected report endpoint. Set approved environment values, save as test_access_control.py, then run python -m unittest -v.
# test_access_control.py
import json
import os
import unittest
from urllib.error import HTTPError
from urllib.parse import urlparse
from urllib.request import Request, build_opener, HTTPRedirectHandler
BASE_URL = os.getenv('API_BASE_URL', 'http://127.0.0.1:8080')
READER_TOKEN = os.getenv('READER_TOKEN', 'valid-reader-test-token')
NO_EXPORT_TOKEN = os.getenv('NO_EXPORT_TOKEN', 'valid-no-export-test-token')
ALLOWED_HOSTS = {'127.0.0.1', 'localhost', 'api.test.example'}
if urlparse(BASE_URL).hostname not in ALLOWED_HOSTS:
raise RuntimeError('Refusing to test an unapproved host')
class NoRedirects(HTTPRedirectHandler):
def redirect_request(self, req, fp, code, msg, headers, newurl):
return None
def get(path, token=None):
headers = {'Accept': 'application/problem+json'}
if token is not None:
headers['Authorization'] = f'Bearer {token}'
request = Request(f'{BASE_URL}{path}', headers=headers, method='GET')
opener = build_opener(NoRedirects())
try:
response = opener.open(request, timeout=10)
return response.status, response.headers, response.read()
except HTTPError as error:
return error.code, error.headers, error.read()
class AccessControlTests(unittest.TestCase):
def test_missing_token_returns_401_with_bearer_challenge(self):
status, headers, body = get('/v1/reports/monthly')
self.assertEqual(status, 401)
self.assertTrue(headers['WWW-Authenticate'].lower().startswith('bearer'))
self.assertEqual(json.loads(body)['status'], 401)
def test_valid_token_without_export_permission_returns_403(self):
status, _, body = get('/v1/reports/monthly/export', NO_EXPORT_TOKEN)
self.assertEqual(status, 403)
self.assertEqual(json.loads(body)['code'], 'insufficient_permission')
def test_valid_reader_can_read_report(self):
status, _, body = get('/v1/reports/monthly', READER_TOKEN)
self.assertEqual(status, 200)
self.assertIn('period', json.loads(body))
if __name__ == '__main__':
unittest.main()
All used classes and methods are public Python APIs. The token fixtures and error codes belong to the example service contract. In a real suite, obtain short-lived valid tokens through a controlled fixture and reserve literal fallback tokens for a local stub. Never commit real credentials.
The no-redirect handler is important if an edge mistakenly sends API callers to an HTML login page. A test should report that redirect rather than following it and failing later on an unrelated 200 document.
7. Test OAuth Bearer Scope and Audience Semantics
For an OAuth-protected resource, token validity and permission are distinct. A token can be active, correctly signed, unexpired, issued by the trusted issuer, and intended for this resource server, yet lack reports:export. That is an authorization failure. The bearer-token specification associates insufficient scope with 403, and the resource server can include a Bearer challenge whose scope parameter identifies scope needed for access.
Test exact scope boundaries. A read scope must not imply write. Similar prefixes such as order:read and orders:read must not match accidentally. Case sensitivity and separator rules should follow issuer policy. A token with a broad administrative scope should succeed only where that scope is deliberately accepted. Unknown or duplicated scope strings must not grant permission through weak substring checks.
Audience prevents a token minted for one API from being replayed at another. Mint a valid token for service A and send it to service B. Expect authentication rejection, typically 401, because the credential is not valid for the target resource. Do not classify wrong audience as insufficient business scope. Test issuer confusion and token-type confusion similarly.
When a client receives 403 for insufficient scope, refreshing the same grant may not help unless user consent or server assignment changes. Client UX should explain the safe next action without exposing internal policy names. A machine client should stop blind retries. Rate-limit or alert on repeated forbidden access as appropriate, but do not convert all 403 responses into account lockout.
Use claims only after signature and credential validation. Unit tests should prove the authorization layer cannot be called with an unverified claims object through an alternate code path.
8. Handle 403 versus Concealment with 404
A server is allowed to hide the existence of a forbidden target by responding as though it did not exist. This can reduce direct enumeration. For example, a user requesting another tenant's private document might receive the same 404 shape as a random nonexistent document. That does not change internal authorization: the server must still prevent access before data retrieval or disclosure.
Choose concealment deliberately. An internal admin API may use 403 because operators benefit from knowing the resource exists but access is blocked. A consumer privacy API may use 404 across tenants. Tests should assert the policy by resource class and operation. Do not demand 403 universally.
Consistency includes more than status. Compare media type, body schema, headers, size ranges, caching, and timing carefully within an approved environment. Perfect timing equality is rarely a realistic test assertion, but gross differences can create an existence oracle. Search, list counts, autocomplete, exports, error messages, logs visible to customers, and presigned storage URLs must follow the same concealment model.
Concealment must not break support and audit. Internal authorized logs can record the real policy decision and safe identifiers while the public response remains generic. Ensure those logs are access-controlled and do not contain bearer tokens or excessive personal data.
A 404 response should never be used to hide a server exception or missing permission configuration. Setup tests should verify the policy engine loaded expected rules. Observability should distinguish true not found from concealed forbidden internally using bounded codes, without exposing that distinction publicly.
9. Cover Sessions, Cookies, CSRF, and Browser Navigation
Browser applications often use session cookies rather than Authorization headers. A missing, expired, invalidated, or incorrectly scoped session maps to authentication failure. The API can return 401 JSON while page navigation redirects to a login URL. Test the two interfaces separately. An XHR that receives an HTML login page with 200 can cause JSON parsing errors and unsafe UI behavior.
Cookie attributes are part of the fixture. Secure, HttpOnly, SameSite, domain, path, and expiry rules determine whether the browser sends the session. A 401 can be caused by client cookie policy rather than server token validation. Inspect the request in browser automation and test cross-site navigation according to the real deployment topology. Never weaken cookie policy merely to make a test pass.
CSRF is distinct from authentication. A request can carry a valid session but lack a required anti-CSRF token or trusted origin. Many applications return 403 for CSRF rejection, though status and response are framework-specific. Create one valid session fixture, vary only CSRF evidence, and assert no mutation. Do not misdiagnose the result as a role-permission failure.
After a 401, the UI can offer reauthentication and safely resume a non-destructive action. It should not automatically replay a high-risk mutation without idempotency protection and user context. After a 403, the UI should not loop through login because the established identity is already valid. It should show an accessible permission message or route to an allowed area.
A browser test should confirm focus, announcement, Back behavior, and removal of stale protected data from the screen. Client-side hiding of a button is useful UX, not authorization. Call the endpoint directly with the same principal and require server enforcement.
10. Verify No Data, State, Cache, or Side-Channel Leakage
For every 401 and 403, assert the mutation did not occur. Query state through an authorized administrative test oracle, not through the same forbidden principal. Check external effects such as emails, exports, messages, charges, approval events, and audit success records. A controller can return 403 after a downstream call has already escaped. Authorization must happen before protected work.
Response bodies should contain a safe problem representation, never the protected resource, policy source code, group membership, token claims, internal paths, or stack traces. Headers must not expose resource ETags, filenames, storage locations, owner IDs, or private cache metadata on rejection. Content length and timing should not make bulk enumeration easy, although precise side-channel testing requires a controlled security methodology.
Shared caching is especially dangerous. Authenticated success responses and access denials need appropriate Cache-Control and Vary behavior. A CDN must not cache one user's 200 and serve it to an unauthenticated user, or cache one tenant's 403 for an authorized tenant. Test at the deployed edge with synthetic accounts. Include logout and permission-revocation behavior with a fresh request, not only browser UI changes.
File and image delivery often bypasses the main API through signed URLs or a CDN. Test expiry, tenant ownership, path guessing, content disposition, and referrer policy. Removing access in the application must have a documented effect on already issued links.
Pair these checks with API contract testing with Pact when consumers depend on exact challenge headers and error schemas.
11. Design the HTTP Status 401 vs 403 Test Matrix
Build separate credential and permission dimensions. A practical matrix includes:
- No credential -> 401 and valid challenge.
- Wrong authentication scheme -> documented 401 behavior.
- Malformed token -> 401 without parser detail.
- Invalid signature, issuer, or audience -> 401.
- Expired, not-yet-valid, revoked, or inactive token -> 401.
- Valid token and exact required permission -> success.
- Valid token missing role or permission -> 403.
- Valid token missing OAuth scope -> 403 with safe Bearer scope guidance when specified.
- Owner and nonowner in same tenant -> allowed and denied pair.
- Same resource ID across tenants -> isolation and concealment policy.
- Allowed role but forbidden resource state -> documented policy response.
- Field-level read and write -> protected fields absent or immutable.
- Alternate list, search, export, file, and batch paths -> identical enforcement.
- Invalid credential plus malformed body -> secure precedence.
- Permission revoked during session -> cache and token-lifetime policy.
- Forbidden mutation -> unchanged state and no downstream effect.
Capture exact status, WWW-Authenticate, media type, stable code, safe detail, cache headers, correlation ID, state, side effects, and audit decision. Use test fixture names that describe effective permissions, such as valid_orders_reader, not ambiguous personas such as user2.
Run deterministic access checks in every relevant change. Put key rotation, revocation propagation, browser cookie, gateway cache, concurrent policy change, and side-channel studies at the layers where they can be controlled. Never compensate for flaky shared identities by broadening assertions to 401 or 403. Fix the fixture.
12. Test Auditing, Monitoring, and Permission Changes
Access decisions need observable, privacy-aware evidence. An audit record can include time, safe principal reference, tenant, endpoint template, action, decision, bounded reason code, policy version, and request correlation ID. It should not include raw access tokens, session cookies, secret claims, full request bodies, or high-risk personal data without a defined need.
Test one successful and one denied action and correlate each to the expected audit event. A 401 may have no principal identity, so record a safe credential fingerprint or anonymous classification only when policy permits. A 403 should identify the authenticated actor internally while the public response remains minimal. Duplicate retries should not create misleading business-success events. Security-denial events may be counted separately.
Monitoring can track 401 and 403 rates by endpoint template, client, and bounded reason. A sudden 401 spike can indicate key rotation, clock, issuer, audience, cookie, or gateway problems. A 403 spike can indicate a permission rollout, missing scope, tenant mapping, or policy-cache problem. Raw resource IDs and subjects should not become metric labels.
Permission changes introduce propagation windows. Remove a role or group assignment, then verify when existing tokens, introspection caches, policy caches, sessions, and edge caches stop authorizing. The expected delay must be documented. High-risk revocation may require short tokens or active checks. Tests should use an injected clock or approved short-lived configuration rather than waiting for normal production lifetimes.
Also test restoration. Granting a permission should enable only the intended operation, not wildcard neighbors. Reauthentication or token refresh requirements should be clear to the client.
Interview Questions and Answers
Q: What is the difference between HTTP 401 and 403?
401 means the request lacks valid authentication credentials for the protected resource. 403 means the server refuses the request, commonly after recognizing a valid identity that lacks permission. I test credential validity separately from roles, scopes, tenant, and ownership.
Q: Why is 401 called Unauthorized?
The reason phrase is historical and can be misleading. In practice, 401 is the authentication challenge response, while 403 represents authorization refusal more directly. I rely on protocol semantics and the numeric status, not the English label alone.
Q: What must be checked on a 401 response?
I check a valid WWW-Authenticate challenge for the supported scheme, safe problem content, cache policy, and zero protected data or mutation. I also verify the client reauthenticates safely rather than looping or parsing an HTML login page.
Q: What token cases should return 401?
Missing, malformed, invalid-signature, expired, inactive, wrong-issuer, wrong-audience, and otherwise unacceptable tokens generally fail authentication. Exact public detail depends on the scheme. Tests should use intentionally minted fixtures and never log the token.
Q: When should insufficient OAuth scope return 403?
When the bearer token is valid for the resource but lacks required scope, the failure is authorization, so 403 is appropriate under bearer-token semantics. A Bearer challenge can safely identify required scope according to the contract. The same invalid token should not reach scope evaluation.
Q: Can an API return 404 instead of 403?
Yes. It can conceal the existence of a forbidden resource. I test that policy consistently across item, list, search, export, file, timing, and body behavior while retaining accurate internal audit evidence.
Q: How do you test role-based access control?
I build an operation matrix and pair the least-privileged allowed principal with a nearby denied principal. I include role composition, group inheritance, tenant, ownership, field rules, and alternate endpoints. Both response and authoritative state are verified.
Q: What is the biggest access-control testing mistake?
Testing only UI visibility or one item endpoint is a major gap. The server must enforce the same policy on direct calls, lists, searches, exports, batch routes, files, and events. I also check caches and downstream effects so a denied response cannot hide leaked work.
Common Mistakes
- Saying 401 means unauthorized permission and 403 means the user needs to log in.
- Omitting or ignoring WWW-Authenticate on a 401 response.
- Using an invalid token to test insufficient scope, which fails before authorization.
- Reusing vague admin and user fixtures without verifying effective permissions.
- Testing role only while ignoring tenant, ownership, resource state, field policy, and alternate data paths.
- Assuming every forbidden resource must return 403 and rejecting deliberate 404 concealment.
- Returning an HTML login page with 200 to API clients.
- Hiding a UI button and treating that as server-side authorization.
- Logging bearer tokens, cookies, sensitive claims, or protected response bodies on failures.
- Checking denial status after the service already wrote state, queued work, or populated a shared cache.
Conclusion
The http status 401 vs 403 distinction is simple to state and demanding to test. Use 401 when valid authentication credentials are missing or unacceptable, with an appropriate challenge. Use 403 when the server refuses an understood request, commonly because a valid principal lacks the required permission. Apply an intentional 404 concealment policy where resource privacy requires it.
Begin with one protected mutation. Create a valid allowed token, a valid underprivileged token, and invalid credential fixtures. Assert the exact status and challenge, then prove unchanged state, no downstream work, safe caching, and accurate audit evidence. Repeat across every route that exposes the same resource. That is how a status distinction becomes real access control.
Interview Questions and Answers
Explain HTTP 401 vs 403 in an interview.
401 means valid authentication credentials are missing or unacceptable and the server issues an authentication challenge. 403 means the server understood the request but refuses it, commonly because the authenticated principal lacks permission. I test the two dimensions with different fixtures.
What would you assert on a 401?
I assert exact 401, the correct WWW-Authenticate scheme and safe parameters, a documented error representation, and appropriate cache controls. I also prove no protected data, state mutation, or side effect occurred. Real credentials never enter logs.
How do you create a true 403 test?
I mint or obtain a valid token for the correct issuer and audience, then intentionally omit the required permission or scope. That ensures authentication passes and authorization is the failing layer. I verify public denial and internal audit reason.
Why can an expired token not test 403?
An expired token is not a valid credential, so it should fail authentication and produce 401 under the scheme. Its role or scope claims should never be trusted. A 403 fixture needs a valid credential with insufficient authority.
When would you return 404 instead of 403?
I use 404 concealment when revealing that a protected resource exists would create privacy or enumeration risk. The policy must cover item, list, search, files, response shape, caches, and gross timing behavior. Internal logs can still record forbidden accurately.
How do OAuth scopes affect 401 and 403?
A token invalid for the resource, such as wrong audience or expiry, produces 401. A valid token lacking required scope produces 403, with scope guidance when the bearer contract specifies it. Tests must avoid weak substring scope matching.
How do you test access control beyond roles?
I add tenant, ownership, relationship, field, resource-state, and environmental dimensions. I test every alternate path such as collection, search, export, batch, file, and event access. A nearby allowed and denied pair proves least privilege.
How should a browser react differently to 401 and 403?
A 401 can trigger safe reauthentication, while a 403 should present a permission outcome rather than looping through login. The UI must clear stale protected content, provide accessible feedback, and avoid replaying sensitive mutations without idempotency protection. Direct API calls must still enforce the same server-side policy.
Frequently Asked Questions
What is the difference between HTTP 401 and 403?
401 means valid authentication credentials are missing or unacceptable for the target resource. 403 means the server refuses the request, commonly because a valid authenticated principal lacks sufficient permission. The test fixtures must separate credential validity from authorization.
Does HTTP 401 mean the user is unauthorized?
The reason phrase Unauthorized is historical. The operational meaning is an authentication challenge, so missing, invalid, expired, or otherwise unacceptable credentials commonly produce 401. Permission denial is more commonly represented by 403.
Does a 401 response require WWW-Authenticate?
Yes, a 401 response includes at least one applicable WWW-Authenticate challenge. Test the supported scheme and safe required parameters. Ensure gateways do not remove or replace it incorrectly.
Should an expired bearer token return 401 or 403?
An expired token is no longer a valid authentication credential, so 401 is the normal result. A valid token that lacks required scope is an authorization problem and normally receives 403 under bearer-token semantics.
Can an API return 404 instead of 403?
Yes. A server can conceal that a forbidden resource exists by returning 404. The policy should be consistent across bodies, lists, search, files, timing, and caches while internal auditing records the true decision safely.
How do I test 401 and 403 responses?
Use no credential and deliberately invalid credentials for 401 cases. Use a valid token with intentionally missing role, scope, tenant, or ownership for 403 cases. Verify headers, safe body, unchanged state, side effects, caching, and audit data.
What is the difference between authentication and authorization?
Authentication establishes an acceptable identity from credentials. Authorization evaluates whether that principal may perform a specific action on a resource in the current context. A request can authenticate successfully and still be forbidden.