All posts
Networking3 min readWatchFor Team

401 vs 403: Unauthorized vs Forbidden

401 and 403 are the two 'you can't have this' codes — and they're constantly confused. Here's the simple rule for telling them apart, with examples.

401 vs 403: Unauthorized vs Forbidden

Two HTTP codes mean "access denied," and developers mix them up daily: 401 Unauthorized and 403 Forbidden. Using the wrong one confuses clients and makes debugging harder. The good news: one short rule sorts them out forever.

The one-rule difference

It comes down to identity:

401 = "I don't know who you are." (Authenticate first.) 403 = "I know who you are — and you still can't." (Permission denied.)

A 401 is about authentication (proving who you are). A 403 is about authorization (what you're allowed to do once you're known). And here's a naming irony worth noting: the code literally named "Unauthorized" (401) is actually about authentication, not authorization.

Side by side

401 Unauthorized403 Forbidden
MeansNot authenticatedAuthenticated, but not permitted
The question"Who are you?""Are you allowed?"
FixLog in / send valid credentialsGet the right permissions
Will retrying with login help?✅ Yes❌ No
Typical triggerMissing/expired tokenValid token, insufficient role

A quick analogy

Think of a members-only club:

  • 401 — you're at the door with no membership card. "Show your card." Once you do, you're in.
  • 403 — you're a member, card and all, but you're trying to enter the staff-only room. Your membership is valid; you're just not allowed there. Showing your card again changes nothing.

Examples

ScenarioCode
Calling an API with no auth token401
Token expired401
Logged-in user opening another user's data403
A "member" hitting an admin-only endpoint403
Valid login, wrong account/tenant403

Why getting it right matters

For APIs, the distinction is a contract. A client that gets a 401 should try to refresh its token and retry; a client that gets a 403 should not retry — it'll just fail again. Returning the wrong code sends clients into pointless retry loops or makes them give up when a re-auth would've worked.

It also matters for monitoring: on a protected endpoint, a 401 or 403 might be the expected, healthy response — so configure checks to treat it as such, and only alert when the code is wrong for that endpoint.

The bottom line

In one line
401Not authenticated — "log in."
403Authenticated but not permitted — "you can't, even logged in."
Rule401 = who are you; 403 = are you allowed.
APIsRetry after re-auth on 401; don't retry on 403.

Remember the club: 401 is the front door, 403 is the staff room. Get the code right and your APIs (and your debugging) get a lot clearer.

Deep dives: 403 Forbidden and HTTP status codes explained.

Share this article