Free & open · no paywall, ever

IntegrAuth Academy

Identity, security and practical AI — free, from zero. Byte-sized lessons, real diagrams, hands-on labs, zero fluff. Two programs, each with its own exam and certificate.

20 tracks 241 lessons 242 hands-on labs 230+ diagrams 100% free

English is hard? Your browser can translate this page into Tamil, Telugu, Kannada, Malayalam or Hindi. Tech words stay in English so you learn the real names.

How?
  • Chrome on phone: ⋮ menu → Translate
  • Chrome on computer: right-click → Translate to …
  • Edge: the translate icon in the address bar
Identity & API Security Track 6 · API Security
0/166 lessons read
API SECURITY · LESSON 2

Basic, bearer & the Authorization header

Every credential on the sign-in menu travels inside an HTTP request. Your goal: send credentials the safe way, and read 401 and 403 answers.

Key points
  • Send credentials in the Authorization header, never in the URL.
  • Basic is a Base64-encoded password. Anyone can decode it.
  • Basic splits at the first colon.
  • 401 means no valid credentials. 403 means known, but not allowed.
  • Hide credentials in logs.

One header, many schemes

HTTP has one standard place to prove who you are: the Authorization header. It holds a scheme name, a space, then the credentials. Three common schemes:

  • Authorization: Basic bWF5YTpzM2NyZXQ= — a username and password.
  • Authorization: Bearer eyJhbGciOi… — an OAuth access token.
  • Authorization: DPoP eyJhbGciOi… — a token tied to a key. A separate DPoP proof header comes with it. See stolen-token defenses II.

If a request has no valid credentials, the server answers 401 Unauthorized. It MUST add a WWW-Authenticate header. It names the scheme the server wants. Example: WWW-Authenticate: Bearer realm="orders". See HTTP basics.

Basic: a password in thin disguise

Basic joins username:password with a colon. Then it Base64-encodes the result. bWF5YTpzM2NyZXQ= is just maya:s3cret. Anyone can decode it, with no key. That is encoding, not encryption. So use Basic only inside TLS (the https padlock).

The first colon splits the two parts. A username can never contain a colon. A password can. So admin:P@ss:w0rd means user admin and password P@ss:w0rd.

A machine can use Basic to sign in to an OAuth token endpoint (client_secret_basic). The client id and client secret go in the header. Both must be URL-encoded before Base64. If not, a secret with + or % fails with invalid_client.

Bearer: holding it is permission

A bearer token works for whoever holds it. Send it in the Authorization header. Never put it in the URL, like ?access_token=….

Why web addresses leak, even over HTTPS

Over HTTPS, the path and the query string are encrypted on the wire. The leak happens at the two ends. People treat a URL as a harmless label and copy it everywhere:

  • Logs. Servers, proxies and gateways write the full URL of every request. A line like GET /v1/orders?api_key=k_live_7Qm… can sit there for a year.
  • Browser history and bookmarks keep every URL.
  • The Referer header tells the next page where you came from. It carries the full URL on requests to the same site. Browsers trim it to the site name when you go to another site.

Put an API key in a header, such as X-API-Key. Never put it in the query. Found one in a log? Rotate the key and make the API reject credentials in query strings.

Think of it like…

mailing a house key. The header puts the key inside the sealed envelope. The URL tapes it to the outside, next to the address. Every post office that writes down the address now knows your key.

One HTTP request (inside TLS)GET /v1/orders?access_token=eyJ…request line: the URL, copied everywhereAuthorization: Bearer eyJ…header: read by the API, not logged by defaultserver & proxy access logsbrowser history & bookmarksReferer to the next pagescreenshots, tickets, analyticsthe API — and nowhere elseapp debug log: Authorization: [REDACTED]
Figure — Same token, two seats. In the URL, a token is copied into logs and history. In the Authorization header, it reaches only the API.

When the server says no: 401 or 403?

Two status codes carry most refusals.

  • 401 means: "I have no valid credentials from you." Get a valid token and retry. This also holds when the token is expired, revoked or malformed (invalid_token).
  • 403 means: "I know who you are, and the answer is still no." The error insufficient_scope means the app needs more permission. A new token of the same kind will not help.
  • 400 with invalid_request means the request is broken. For example, the token was sent two ways at once. Fix the request.
Go deeper: Bearer rules and error table

RFC 6750 allows three ways to send a bearer token. The Authorization header is the one every server MUST support. A form-body field is allowed only in narrow cases. A query parameter was allowed in 2012 with a warning. RFC 9700 (January 2025) says clients MUST NOT use it. A client must not use two methods in one request.

What went wrongStatusChallengeWhat the client does
No credentials401Bearer realm="orders"Get a token and send it.
Token expired, revoked or malformed401error="invalid_token"Get a fresh token and retry.
Valid token, not enough permission403error="insufficient_scope", scope="orders:write"Ask for more permission.
Broken request400error="invalid_request"Fix the request.

With client_secret_post, the client sends the secret in the form body. RFC 6749 says this is NOT RECOMMENDED unless the client cannot use Basic. The values MUST NOT go in the web address. Either way it is a shared secret. The menu shows stronger options.

Keep error messages short and generic. "The access token expired" helps a real client. A message that says which check failed helps an attacker.

Watch out

A header is safer than a URL, but not magic. "Log full requests" puts every Authorization header in the logs. Hide Authorization, Proxy-Authorization, Cookie, Set-Cookie and your API-key header. Never log token request and response bodies.

🧪 Interactive lab — enable JavaScript to play with this one.

🧪 Try it free

Use made-up credentials only. Run curl -v -u demo:demo https://httpbin.org/basic-auth/demo/demo to see the Authorization: Basic header. Decode it with echo ZGVtbzpkZW1v | base64 --decode. Then call https://httpbin.org/bearer with no header and read the WWW-Authenticate challenge in the 401 reply. (httpbin.org is a free HTTP testing service.)