snaptxt.app
Blog
Data Tools4 min readNovember 3, 2026

401 vs 403: Which HTTP Status Code Should You Return?

401 Unauthorized and 403 Forbidden are the two HTTP status codes developers mix up most, and the confusion is baked into the spec itself: 401 is literally named "Unauthorized" when it actually means unauthenticated. Here's the distinction that resolves almost every case.

The one-line rule

  • 401 Unauthorized — "I don't know who you are." The request lacks valid authentication credentials, or they're wrong. The fix is to authenticate.
  • 403 Forbidden — "I know who you are, and you can't do this." Authentication succeeded, but the authenticated identity isn't permitted to access the resource. Authenticating again won't help.

Authentication is who you are; authorization is what you're allowed to do. 401 is an authentication failure; 403 is an authorization failure.

Worked examples

  • No token on a protected endpoint → 401. The client should log in and retry with credentials.
  • Expired or malformed token → 401. The credentials are present but not valid.
  • Valid token, but the user is a normal member hitting an admin-only route → 403. They're authenticated fine; they just lack the role.
  • Valid token, but trying to edit another user's resource → 403.

A useful test: would sending valid credentials fix it? If yes, it's 401. If the user is already properly authenticated and it still won't work, it's 403.

The WWW-Authenticate detail

The spec ties a requirement to 401 that's easy to miss: a 401 response must include a WWW-Authenticate header telling the client how to authenticate. 403 has no such requirement — in fact a 403 deliberately says "don't bother, it won't matter." If you're returning 401 without WWW-Authenticate, you're technically out of spec, and 403 is often what you actually meant.

When to hide existence instead

Sometimes you don't want to reveal that a resource even exists to an unauthorized user — 403 confirms "this exists, you can't have it," which leaks information. In those cases some APIs deliberately return 404 Not Found instead of 403, so an attacker can't distinguish "forbidden" from "doesn't exist." That's a security trade-off, not a correctness one, but it's a legitimate pattern for sensitive resources.

Look up any code

For the full reference — every code from 1xx to 5xx with meaning and common causes — see the HTTP Status Codes reference. And for choosing status codes across a whole API, there's a guide on which status code your API should return.

guidehttpapi
H

Hanuman Singh · built snaptxt.app · hanumansingh.dev