HTTP Authentication

WWW-Authenticate

This is the HTTP header a server sends with a 401 Unauthorized response to tell the client how to authenticate. It is not a concrete login mechanism: it is the negotiation protocol that announces which credential scheme the resource accepts.

Standardized in RFC 7235, it is the foundation of authentication discovery on the web: the client does not need to know the method in advance — it learns it from the server's own challenge.

The challenge–response flow

1
GET /resource
The client requests a protected resource without credentials.
2
401 + WWW-Authenticate
The server rejects the request and describes the required scheme in the header.
3
Authorization: …
The client retries with the credential matching the indicated scheme.
4
200 OK
The server validates and delivers the resource.

Step 2 is the key: the WWW-Authenticate header carries the scheme(Basic, Digest, Bearer…) and parameters such as realm,scope, or nonce. The client replies by reflecting that information in the Authorization header.

Why discovery helps the web

Zero prior configuration. A generic client can reach any resource, receive a 401, and instantly know which credential to prepare.

Interoperability. Browsers, HTTP libraries, and agents all speak the same language. The server changes its auth policy and clients adapt on their own.

Evolution without breaking clients. With RFC 9728 the challenge can point to a metadata document, chaining discovery of authorization servers, scopes, and endpoints. This is what makes ecosystems like OAuth, OIDC, agents, and MCP viable.

Authentication schemes

BasicRFC 7617Not recommended

Sends username and password Base64-encoded on every request. Base64 is not encryption — anyone who intercepts the header reads the password in plain text.

Server challenge
WWW-Authenticate: Basic realm="demo"
  • ·Instantly reversible: atob("dXNlcjpwYXNzd29yZA==") → "user:password".
  • ·Requires HTTPS at all times; without TLS the credential travels in the clear.
  • ·No expiration or revocation: the credential is valid until the password changes.
  • ·The browser shows a native username/password dialog.
Client response
Authorization: Basic dXNlcjpwYXNzd29yZA==
Compatible with
  • All browsers
  • curl / wget
  • Standard HTTP libraries
DigestRFC 7616Legacy

Challenge–response scheme: the server sends a nonce and the client replies with a hash, never the password itself. An improvement over Basic, but MD5 is now weak.

Server challenge
WWW-Authenticate: Digest realm="demo", nonce="…", algorithm=MD5, qop="auth"
  • ·The password never travels over the network, only a derived hash.
  • ·The nonce mitigates replay attacks.
  • ·qop="auth" also protects the HTTP method and request URI.
  • ·Still depends on MD5/SHA-256; less practical than tokens for APIs.
Client response
Authorization: Digest username="user", realm="demo", nonce="…", uri="/demo/digest", response="…", qop=auth, nc=00000001, cnonce="…"
Compatible with
  • All browsers
  • curl / wget
  • HTTP libraries with Digest support
BearerRFC 6750Recommended for APIs

The client carries an access token (often a JWT) issued by an authorization server. "Anyone who holds it can use it" — that's why the token must be protected like a credential.

Server challenge
WWW-Authenticate: Bearer
  realm="demo",
  scope="read write",
  error="invalid_token",
  error_description="The token has expired or is invalid",
  error_uri="https://…/docs/errors/invalid_token"
  • ·realm (optional) — protection scope; must not appear more than once.
  • ·scope (optional) — space-separated list of required scopes, e.g. "read write".
  • ·error (optional) — rejection reason: invalid_request · invalid_token · insufficient_scope.
  • ·error_description (optional) — human-readable error explanation, for developers only.
  • ·error_uri (optional) — absolute URI pointing to error documentation.
  • ·If the token is a JWT, its header and payload are readable (not encrypted) — never store secrets inside.
Option A · Explicitly defined URL (out-of-band)
# The client knows the token endpoint in advance (docs, SDK, config)
→ POST https://auth.example.com/token
   grant_type=client_credentials&scope=read
← 200 { "access_token": "eyJ…", "token_type": "Bearer", "expires_in": 3600 }
Option B · Inferred URL via RFC 8414 (issuer known)
# If the issuer is known, the AS metadata URL is inferred:
→ GET https://auth.example.com/.well-known/oauth-authorization-server
← 200 {
    "token_endpoint": "https://auth.example.com/token",
    "authorization_endpoint": "https://auth.example.com/authorize"
  }
# OIDC fallback if 404:
→ GET https://auth.example.com/.well-known/openid-configuration
Client response
Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9…
  • ·RFC 6750 does not include the AS URL in the challenge — the client must know it in advance or infer it.
  • ·Option A (defined): the token endpoint is configured explicitly in the client (SDK, env var, docs).
  • ·Option B (inferred): if the issuer is known, construct /.well-known/oauth-authorization-server per RFC 8414.
  • ·For fully automatic discovery from the 401 challenge, use Bearer + Discovery (RFC 9728).
Compatible with
  • API clients (curl, Postman, SDKs)
  • fetch / XMLHttpRequest
  • OAuth 2.0 clients
Bearer + DiscoveryRFC 9728Modern · Discovery

OAuth 2.0 Protected Resource Metadata. The 401 challenge no longer just says "you need a Bearer token": it points to a metadata document describing WHERE and HOW to obtain one. The client discovers everything automatically.

Server challenge
WWW-Authenticate: Bearer resource_metadata="https://…/.well-known/oauth-protected-resource.json"
  • ·resource_metadata — the only challenge parameter; URL of the resource metadata document.
  • ·The client extracts authorization_servers[0] as the AS issuer identifier.
  • ·Enables generic clients: they discover the full flow from a single 401.
  • ·Key for ecosystems like agents and MCP, where the client does not know the issuer in advance.
1 · Resource returns 401
← 401 WWW-Authenticate: Bearer resource_metadata="https://…/.well-known/oauth-protected-resource.json"
2 · Resource metadata — RFC 9728
→ GET https://…/.well-known/oauth-protected-resource.json
← 200 {
    "resource": "https://…/demo/bearer2",
    "authorization_servers": ["https://auth.example.com"],
    "scopes_supported": ["read", "write"]
  }
3a · AS Metadata — RFC 8414
→ GET https://auth.example.com/.well-known/oauth-authorization-server
← 200 {
    "issuer": "https://auth.example.com",
    "authorization_endpoint": "https://auth.example.com/authorize",
    "token_endpoint": "https://auth.example.com/token",
    "scopes_supported": ["read", "write"],
    "grant_types_supported": ["authorization_code", "client_credentials"]
  }
3b · Fallback — OpenID Connect Discovery
→ GET https://auth.example.com/.well-known/openid-configuration
← 200 {
    "issuer": "https://auth.example.com",
    "authorization_endpoint": "https://auth.example.com/authorize",
    "token_endpoint": "https://auth.example.com/token",
    "userinfo_endpoint": "https://auth.example.com/userinfo",
    "jwks_uri": "https://auth.example.com/jwks"
  }
4 · Obtain token and retry
→ POST https://auth.example.com/token
← 200 { "access_token": "eyJ…", "token_type": "Bearer", "expires_in": 3600 }

→ GET https://…/demo/bearer2
   Authorization: Bearer eyJ…
← 200 OK
  • ·Step 3a — RFC 8414: looks up /.well-known/oauth-authorization-server[/{path}] using the issuer.
  • ·Step 3b — If 404, falls back to OpenID Connect Discovery: /.well-known/openid-configuration.
  • ·URL construction follows the same rule: well-known inserted between the host and path of the issuer.
  • ·The AS document exposes authorization_endpoint, token_endpoint, scopes_supported, grant_types…
  • ·With those endpoints the client completes the OAuth flow and obtains a valid Bearer token.
Compatible with
  • MCP clients
  • AI agents
  • Modern OAuth 2.0 clients (RFC 9728)

Glossary

AS
Authorization Server — the server that issues access tokens after verifying the client's identity.
RS
Resource Server — the server hosting the protected resource, which validates the presented token.
Bearer
Token scheme where "whoever holds it, uses it." The token must be protected like a credential.
JWT
JSON Web Token — a signed (and optionally encrypted) token whose header and payload are Base64-readable.
Scope
Requested access level, e.g. "read write". The AS may grant a subset of the requested scopes.
Nonce
Number used once. In Digest it prevents replay attacks; in OIDC it binds the token to the client.
Realm
String identifying the protection space. Multiple paths on the same server can share a realm.
Issuer
Canonical identifier of the AS (URL). Used to derive discovery URLs without prior configuration.
OIDC
OpenID Connect — an identity layer on top of OAuth 2.0 that adds an ID Token with user data.
MCP
Model Context Protocol — AI agent protocol that uses Bearer + Discovery (RFC 9728) for authentication.