Question 10 · Section 6

What is the difference between 401 and 403?

The difference between 401 Unauthorized and 403 Forbidden is the difference between "who are you?" and "what are you allowed to do?".

Language versions: English Russian Ukrainian

Junior Level

The difference between 401 Unauthorized and 403 Forbidden is the difference between “who are you?” and “what are you allowed to do?”.

401 Unauthorized — “I don’t know you”

  • The server doesn’t recognize the user
  • You need to log in
  • Example: You showed up at work without a badge
GET /profile
→ 401 Unauthorized
→ Frontend redirects to the login page

403 Forbidden — “I know you, but you’re not allowed”

  • The server knows the user but forbids the action
  • Re-logging won’t help — it’s a permissions issue
  • Example: You have a badge for the office, but not for the server room
GET /admin
→ 403 Forbidden
→ Frontend shows "Access denied"

Simple analogy:

  • 401: The guard asks: “Who are you?” (need to show ID)
  • 403: The guard says: “I know you, Ivanov, but you’re not allowed in this office”

Middle Level

401 Unauthorized (Identity Unknown)

  • Essence: The server doesn’t know the user
  • RFC 9110 Requirement: RFC 9110 requires that a 401 response contain a WWW-Authenticate header (e.g., WWW-Authenticate: Bearer realm="api"). However, in production an API Gateway may strip it — this is normal for token-based authentication.
  • Action: Typical frontend behavior — refresh the token via Refresh Token Flow or redirect to the login page.

403 Forbidden (Identity Known)

  • Essence: The server knows the user but forbids the action
  • Action: Re-logging won’t help. This is a permissions issue (Scopes, Roles, ACL).
    • Scopes — API-level permissions (e.g., read:users).
    • Roles — user roles (ADMIN, USER).
    • ACL (Access Control List) — mapping table of users and resources.

Implementation in Spring Security 6.x

In Spring Security, these two errors are handled by different components:

  1. AuthenticationEntryPoint: Triggers when an anonymous user tries to access a protected endpoint (generates 401)
  2. AccessDeniedHandler: Triggers when a logged-in user’s GrantedAuthority is insufficient (generates 403)

Edge Cases

  • Expired Token: If the JWT is expired — return 401, not 403. Mobile apps use 401 as a trigger to refresh the session
  • IP Blocking / Rate Limiting: 403 may be used for IP blocking (WAF). The user is authenticated, but the infrastructure denies access
  • CSRF: In Spring Security, a missing or invalid CSRF token results in 403 Forbidden, even if the user is a super-admin

Diagnostics

  • A spike in 401s may indicate problems with the Identity Provider (Keycloak, Auth0) or a Brute-force attack
  • Persistent 403s from legitimate users — sign of a bug in the UI or role mapping

Senior Level

When NOT to use 401/403

  • Don’t return 401 for public resources — it’s confusing
  • Don’t use 403 for rate limiting — use 429 Too Many Requests for that
  • For non-existent resources, 404 is better than 403 (to avoid revealing existence)

Security by Obscurity (Hiding via 404)

Sometimes, if a user tries to access a secret resource (e.g., /admin/top-secret), the server may return 404 Not Found instead of 403 Forbidden.

Why? So that an attacker doesn’t know whether the resource exists at all. A 403 response confirms the resource’s existence (“it’s here, but I won’t give it to you”).

OAuth2 Scopes vs Roles

In modern systems, 403 often arises from insufficient Scopes in the JWT token:

  • You have the USER role (authorization passed)
  • But the token lacks the write scope (access to the POST method is denied)

Spring Security Components (details)

AuthenticationEntryPoint

Handles situations where an unauthenticated user tries to access a protected resource. Should initiate the authentication process.

AccessDeniedHandler

Handles situations where an authenticated user lacks the necessary permissions. Can log unauthorized access attempts.

Diagnostics and Monitoring

  • Metric: auth_failures_total: A spike in 401s — problems with the Identity Provider or a Brute-force attack
  • Monitoring 403s: Persistent 403s from legitimate users — a bug in the UI (buttons without permissions) or in role mapping
  • Audit Logging: All 403 responses should be logged with the user ID and required permission for the security team

Interview Cheat Sheet

Must know:

  • 401 Unauthorized = “don’t know who you are” — needs authentication, typical action — redirect to login
  • 403 Forbidden = “know you, but you can’t” — permissions issue (roles, scopes, ACL)
  • 401 per RFC 9110 must contain the WWW-Authenticate header
  • In Spring Security: AuthenticationEntryPoint → 401, AccessDeniedHandler → 403
  • Expired JWT = 401 (not 403), mobile apps use 401 to trigger session refresh
  • Security by Obscurity: sometimes return 404 instead of 403 to avoid confirming resource existence
  • Rate limiting = 429, not 403; CSRF error = 403 even for super-admin

Common follow-up questions:

  • What should the frontend do on 401? — Refresh the token via Refresh Token or redirect to login
  • What should the frontend do on 403? — Show “access denied”, re-login won’t help
  • When is it better to return 404 instead of 403? — For secret resources, to avoid confirming their existence
  • How do Scopes differ from Roles? — Scopes = API-level permissions (read:users), Roles = user roles (ADMIN, USER)

Red flags (DO NOT say):

  • “401 and 403 are the same” — 401 = not authenticated, 403 = authenticated but no permissions
  • “Rate limiting needs 403” — there’s 429 Too Many Requests for that
  • “Re-logging will fix a 403” — 403 = permissions issue, not authentication
  • “Expired Token = 403” — expired token = 401, client should refresh the session

Related topics:

  • [[What HTTP status codes do you know]]
  • [[What does Stateless mean in the context of REST]]
  • [[What is REST]]
  • [[What is RESTful API design]]
  • [[How to properly name REST endpoints]]