1. Library
  2. Computer Networks
  3. Http and the Web
  4. Headers

Updated 9 hours ago

Every protected resource on the Internet asks the same question: Who are you, and how do I know you're telling the truth?

The Authorization header is your answer. It's a single line in an HTTP request that carries whatever proof the server demands—a password, a token, a cryptographic signature. Get it right, and you're in. Get it wrong, and you get a 401 Unauthorized telling you to try again.

The Shape of Authorization

Every Authorization header follows the same pattern:

Authorization: <scheme> <credentials>

The scheme tells the server how you're proving yourself. The credentials are the proof itself. Different schemes represent different answers to an old question: How do I prove I'm me without giving away too much?

Basic Authentication: The Honest Approach

Basic auth is disarmingly simple. You send your username and password, separated by a colon, encoded in Base64:

Authorization: Basic YWxpY2U6c2VjcmV0MTIz

That gibberish decodes to alice:secret123. Anyone can decode it:

atob('YWxpY2U6c2VjcmV0MTIz'); // Returns: "alice:secret123"

This is the thing about Basic auth: Base64 is a costume, not a disguise. It makes credentials look like gibberish, but it's trivially reversible. You're sending your actual password with every single request—just dressed up so it doesn't look quite so naked in logs.

This sounds terrible, and in some ways it is. But Basic auth survives because of one saving grace: HTTPS. When the entire connection is encrypted, it doesn't matter that the password is only Base64-encoded. The encryption handles the real security. Basic auth just handles the formatting.

Use Basic auth for:

  • Internal tools behind a VPN
  • Development environments
  • Simple scripts talking to APIs you control
  • Anywhere the simplicity is worth more than the sophistication of alternatives

Never use it over plain HTTP. That's sending passwords in postcards.

Bearer Tokens: Possession Is Proof

Bearer tokens flip the model. Instead of proving who you are on every request, you prove it once, get a token, and then present that token as your credential:

Authorization: Bearer eyJhbGciOiJIUzI1NiIs...

The name "bearer" is precise: whoever bears the token gets access. Like a physical key—it doesn't matter who you are, only that you have the key in your hand.

This has profound implications. If someone steals your bearer token, they become you until the token expires. There's no "but I'm the real Alice" appeal. Possession is proof.

JWTs: Tokens That Prove Themselves

Most bearer tokens today are JWTs—JSON Web Tokens. They're clever: instead of being random strings the server must look up in a database, JWTs carry their own proof of validity.

A JWT has three parts, separated by dots:

eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkFsaWNlIn0.signature

Header: Says how the token is signed (algorithm, type) Payload: Contains claims—who you are, when this expires, what you can do Signature: Cryptographic proof that the header and payload haven't been tampered with

The server can validate a JWT by checking the signature against a secret key. No database lookup required. This makes JWTs scale beautifully—any server with the key can validate any token.

The Token Lifecycle

Tokens have a rhythm:

  1. Authenticate once: Send your real credentials to a login endpoint
  2. Receive tokens: Get back an access token (short-lived) and often a refresh token (longer-lived)
  3. Use the access token: Include it in Authorization headers
  4. Refresh when needed: When the access token expires, use the refresh token to get a new one
  5. Re-authenticate eventually: When even the refresh token expires, start over
// Step 1: Trade credentials for tokens
const { accessToken, refreshToken } = await login(username, password);

// Step 2: Use access token for API calls
const response = await fetch('/api/data', {
    headers: { 'Authorization': `Bearer ${accessToken}` }
});

// Step 3: When access token expires, refresh it
const { accessToken: newToken } = await refresh(refreshToken);

Short-lived access tokens (minutes to hours) limit the damage if one is stolen. The refresh token, kept more secure, lets users stay logged in without constantly re-entering passwords.

Digest Authentication: Hashing Instead of Sending

Digest auth tried to solve Basic auth's vulnerability without requiring encryption. Instead of sending your password, you send a hash of your password mixed with a server-provided random value (a "nonce"):

Authorization: Digest username="alice", nonce="abc123", response="hash..."

The server does the same hash calculation. If the results match, you must know the password.

Clever, but complicated. Modern applications have largely abandoned Digest auth in favor of bearer tokens over HTTPS. The encryption handles security; the auth scheme handles identity.

API Keys: Simplified Trust

Many APIs skip the complexity entirely:

Authorization: ApiKey sk_live_abc123xyz

Or in a custom header:

X-API-Key: sk_live_abc123xyz

API keys are bearer tokens without the ceremony. No OAuth flows, no refresh tokens, no expiration (usually). You get a key, you use the key, the key identifies you.

This simplicity is the point. For server-to-server communication where there's no user to log in, API keys cut through the complexity. But they're also less secure—a leaked API key often has no expiration, meaning damage can continue indefinitely.

OAuth 2.0: Authorization as a Service

OAuth isn't a header format—it's a framework for obtaining tokens. It answers a specific question: How can I let a third-party application access my data without giving them my password?

The Authorization Code flow (most common for web apps):

  1. Your app redirects the user to the authorization server (Google, GitHub, etc.)
  2. User logs in there and grants permission
  3. Authorization server redirects back with a code
  4. Your app exchanges that code for an access token
  5. Your app uses that token in Authorization headers

The user's password never touches your application. You get a token with specific, limited permissions (scopes). The user can revoke access anytime.

The result is still a bearer token:

Authorization: Bearer ya29.access-token-from-oauth

OAuth's complexity buys you something valuable: delegated authorization with user consent and granular permissions.

When Authentication Fails

Servers tell you what they want. A 401 Unauthorized response includes a WWW-Authenticate header naming the expected scheme:

HTTP/1.1 401 Unauthorized
WWW-Authenticate: Bearer realm="api", error="invalid_token"

This says: "I need a Bearer token, you sent something invalid." The realm describes what's being protected. The error gives specifics.

For Basic auth:

WWW-Authenticate: Basic realm="Secure Area"

Browsers seeing this will pop up a username/password dialog. That's the Basic auth experience—intrusive but functional.

Security Essentials

HTTPS is non-negotiable. Every authentication scheme assumes encrypted transport. Without it, credentials are exposed regardless of how cleverly they're formatted.

Tokens should expire. Short-lived access tokens (15 minutes to an hour) mean a stolen token has limited utility. Refresh tokens extend sessions without extending risk.

Storage matters. In browsers:

  • HttpOnly cookies can't be read by JavaScript (XSS-resistant)
  • localStorage can be read by any script on your page (XSS-vulnerable)
  • Memory is safest but doesn't survive page refreshes

For mobile apps, use the platform's secure storage: iOS Keychain, Android Keystore.

Never put credentials in URLs. They leak into logs, browser history, and Referer headers:

// Dangerous: credential in URL
fetch('https://api.example.com/data?token=secret');

// Safe: credential in header
fetch('https://api.example.com/data', {
    headers: { 'Authorization': 'Bearer secret' }
});

Validate everything. A well-formed JWT might still be expired, revoked, or signed with the wrong key. Check signatures, expiration, issuer, and audience claims on every request.

Frequently Asked Questions About Authorization Headers

Was this page helpful?

😔
🤨
😃