9 min
  • APIs
  • Authentication
  • HTTP

API authentication

Two questions, constantly confused, and HTTP has a different status code for each:

  • Authentication — who is calling? A failure here is 401 Unauthorized, and the response owes the client a WWW-Authenticate field naming the scheme to use.
  • Authorisation — may this caller do this? A failure here is 403 Forbidden, and there is nothing the client can change about its credentials to fix it.

401 means I do not know you. 403 means I know exactly who you are, and no.

Loading the API Visualizer simulation…

Keys, tokens, and where they must not go

An API key is a long random string that identifies a caller and usually nothing else. A

bearer token is the same idea with structure: it says who you are, what you may do, and when it stops being true.

"Bearer" is the whole security model — possession is sufficient. That has two immediate consequences:

text
Authorization: Bearer eyJhbGciOi...     good: a header, over TLS, not logged by defaultGET /v1/orders?api_key=sk_live_9f3...   bad:  now in access logs, browser history,                                              Referer headers, and every screenshot

A JWT is worth understanding concretely: the payload is base64url, which is an encoding and not encryption. Anyone holding the token can read every claim in it. The signature makes it tamper-evident, not confidential — and a verifier must decide which algorithms it accepts before it reads the token, or it will be told.

Check yourself
You put a user's email and role in a JWT payload. Who can read them?

Acting on somebody else's behalf

The harder problem is an application that needs to use your account somewhere else. Handing it your password gives it everything, forever, with no way to take it back.

OAuth is the answer, and the shape of it is worth holding in your head:

Loading the API Visualizer simulation…

You type your password into the authorization server and nowhere else. It hands the application a short-lived code through the browser; the application exchanges that code for a token over a direct back-channel, so the token itself never travels through the browser at all.

PKCE closes the remaining hole. The client commits to a secret before the user even authenticates, and must produce it at the exchange — so a stolen code is worthless to whoever stole it.

Predict what happens next
An attacker intercepts the authorization code from the redirect URL. What can they do with it?

Key takeaways

  • 401 means the caller is unknown and owes a WWW-Authenticate field; 403 means the caller is known and refused.
  • Bearer means possession is sufficient, so a credential in a query string is a credential in logs, history and Referer headers.
  • A JWT payload is encoded, not encrypted — signing makes it tamper-evident, and readable by anyone holding it.
  • OAuth exists so an application never sees your password: the code travels through the browser, the token never does.
  • PKCE binds the code to the client that began the flow, which makes a stolen authorization code worthless.

Take it further