HTTP

Header

WWW-Authenticate

Learn how the WWW-Authenticate header specifies authentication methods required to access protected resources. Understand Basic, Bearer, and Digest schemes.

4 min read intermediate Try in Playground

TL;DR: Sent with 401 responses to specify required authentication method (Basic, Bearer, Digest). Tells clients how to provide credentials for protected resources.

What is WWW-Authenticate?

WWW-Authenticate tells the client what authentication method is required to access a protected resource. It’s like a bouncer at a club saying “you need to show ID and be on the guest list” - it specifies exactly what credentials are needed and how to provide them.

This header is sent with 401 Unauthorized responses to guide clients on how to authenticate.

How It Works

1. Client requests protected resource:

GET /admin/dashboard HTTP/1.1
Host: example.com
```text

**2. Server responds with authentication challenge:**

```http
HTTP/1.1 401 Unauthorized
WWW-Authenticate: Basic realm="Admin Area"
Content-Type: text/html

<h1>401 Unauthorized</h1>
<p>Please provide valid credentials.</p>

3. Client prompts user for credentials and retries:

GET /admin/dashboard HTTP/1.1
Authorization: Basic dXNlcjpwYXNzd29yZA==
```text

**4. Server validates and responds** with the protected resource.

## Authentication Schemes

### Basic Authentication

Simple username/password authentication:

```http
WWW-Authenticate: Basic realm="Protected Area"

Client encodes credentials in Base64:

Authorization: Basic dXNlcjpwYXNzd29yZA==
```text

(Decodes to `user:password`)

### Bearer Token

Token-based authentication (JWT, API keys):

```http
WWW-Authenticate: Bearer realm="API Access"

Client sends token:

Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...
```text

### Digest Authentication

More secure than Basic (password not sent in plain text):

```http
WWW-Authenticate: Digest realm="Protected", qop="auth", nonce="dcd98b7102dd2f0e8b11d0f600bfb0c093", opaque="5ccc069c403ebaf9f0171e9517f40e41"

Custom Schemes

API-specific authentication methods:

WWW-Authenticate: ApiKey realm="API v1"
WWW-Authenticate: OAuth realm="OAuth 2.0"
```http

## Realm Parameter

The `realm` describes the protected area:

```http
WWW-Authenticate: Basic realm="Admin Panel"
WWW-Authenticate: Basic realm="User Dashboard"
WWW-Authenticate: Basic realm="Financial Data"

Browsers often display the realm in authentication dialogs.

Multiple Authentication Options

Offer multiple authentication methods:

HTTP/1.1 401 Unauthorized
WWW-Authenticate: Basic realm="Protected Area"
WWW-Authenticate: Bearer realm="API Access"
WWW-Authenticate: Digest realm="Secure Zone"
```text

Client can choose which method to use.

## Real-World Examples

### API Authentication

```http
GET /api/users HTTP/1.1

HTTP/1.1 401 Unauthorized
WWW-Authenticate: Bearer realm="API v2", error="invalid_token", error_description="The access token expired"
Content-Type: application/json

{
  "error": "unauthorized",
  "message": "Valid bearer token required"
}

Admin Panel

GET /admin HTTP/1.1

HTTP/1.1 401 Unauthorized
WWW-Authenticate: Basic realm="Administration"
Content-Type: text/html

<!DOCTYPE html>
<html>
<head><title>401 Unauthorized</title></head>
<body>
  <h1>Authentication Required</h1>
  <p>Please log in to access the admin panel.</p>
</body>
</html>
```text

### OAuth 2.0 API

```http
GET /api/profile HTTP/1.1

HTTP/1.1 401 Unauthorized
WWW-Authenticate: Bearer realm="OAuth 2.0", error="invalid_token", error_description="Token has expired"
Content-Type: application/json

{
  "error": "token_expired",
  "message": "Please refresh your access token"
}

File Server

GET /private/documents/report.pdf HTTP/1.1

HTTP/1.1 401 Unauthorized
WWW-Authenticate: Basic realm="Document Server"
Content-Type: text/plain

Authentication required to access private documents.
```text

## OAuth 2.0 Error Parameters

For Bearer token authentication, include error details:

```http
WWW-Authenticate: Bearer realm="API", error="invalid_token", error_description="The token is malformed"

Common error codes:

  • invalid_request - Request is malformed
  • invalid_token - Token is invalid or expired
  • insufficient_scope - Token lacks required permissions

Server Implementation

Express.js Basic Auth

app.get('/protected', (req, res) => {
  const auth = req.headers.authorization

  if (!auth || !auth.startsWith('Basic ')) {
    res.set('WWW-Authenticate', 'Basic realm="Protected Area"')
    return res.status(401).json({
      error: 'Authentication required',
      message: 'Please provide valid credentials'
    })
  }

  const credentials = Buffer.from(auth.slice(6), 'base64').toString()
  const [username, password] = credentials.split(':')

  if (!validateCredentials(username, password)) {
    res.set('WWW-Authenticate', 'Basic realm="Protected Area"')
    return res.status(401).json({
      error: 'Invalid credentials'
    })
  }

  res.json({ message: 'Access granted' })
})
```javascript

### Express.js Bearer Token

```javascript
app.get('/api/data', (req, res) => {
  const auth = req.headers.authorization

  if (!auth || !auth.startsWith('Bearer ')) {
    res.set('WWW-Authenticate', 'Bearer realm="API v1"')
    return res.status(401).json({
      error: 'token_required',
      message: 'Bearer token required'
    })
  }

  const token = auth.slice(7)

  try {
    const decoded = jwt.verify(token, process.env.JWT_SECRET)
    res.json({ data: 'Protected data', user: decoded.sub })
  } catch (error) {
    res.set(
      'WWW-Authenticate',
      'Bearer realm="API v1", error="invalid_token", error_description="Token is invalid or expired"'
    )
    return res.status(401).json({
      error: 'invalid_token',
      message: 'Token is invalid or expired'
    })
  }
})

Python Flask

from flask import Flask, request, jsonify
import base64

@app.route('/protected')
def protected():
    auth = request.headers.get('Authorization')

    if not auth or not auth.startswith('Basic '):
        response = jsonify({'error': 'Authentication required'})
        response.status_code = 401
        response.headers['WWW-Authenticate'] = 'Basic realm="Protected Area"'
        return response

    credentials = base64.b64decode(auth[6:]).decode('utf-8')
    username, password = credentials.split(':', 1)

    if not validate_credentials(username, password):
        response = jsonify({'error': 'Invalid credentials'})
        response.status_code = 401
        response.headers['WWW-Authenticate'] = 'Basic realm="Protected Area"'
        return response

    return jsonify({'message': 'Access granted'})
```text

## Security Considerations

### Basic Authentication Risks

```http
❌ Over HTTP (credentials visible):
WWW-Authenticate: Basic realm="Admin"

✅ Over HTTPS only:
WWW-Authenticate: Basic realm="Admin"
# + Strict-Transport-Security header

Token Security

✅ Include error details for debugging:
WWW-Authenticate: Bearer realm="API", error="invalid_token", error_description="Token expired at 2025-01-15T10:30:00Z"
```text

### Realm Information Disclosure

```http
❌ Too much information:
WWW-Authenticate: Basic realm="Internal Admin Database Server #3"

✅ Generic but helpful:
WWW-Authenticate: Basic realm="Admin Area"

Best Practices

1. Always use HTTPS with Basic authentication:

WWW-Authenticate: Basic realm="Secure Area"
# Only over HTTPS connections
```http

**2. Provide helpful realm descriptions:**

```http
WWW-Authenticate: Basic realm="Customer Portal"
WWW-Authenticate: Bearer realm="API v2"

3. Include error details for APIs:

WWW-Authenticate: Bearer realm="API", error="insufficient_scope", error_description="Token lacks 'admin' scope"
```http

**4. Support multiple authentication methods:**

```http
WWW-Authenticate: Basic realm="Legacy Support"
WWW-Authenticate: Bearer realm="Modern API"

5. Use appropriate status codes:

401 Unauthorized + WWW-Authenticate  # Authentication required
403 Forbidden                       # Authenticated but not authorized

Frequently Asked Questions

What is WWW-Authenticate?

WWW-Authenticate is sent with 401 responses to tell clients how to authenticate. It specifies the authentication scheme (Basic, Bearer, Digest) and parameters like realm.

What authentication schemes are common?

Basic (username:password base64), Bearer (OAuth tokens), and Digest (hashed credentials) are most common. Bearer is standard for modern APIs with JWT or OAuth.

What is the realm parameter?

Realm describes the protected area. Browsers may show it in login prompts. Use descriptive names like "Admin Area" or "API Access" to help users understand what credentials to use.

Can I use multiple authentication schemes?

Yes, send multiple WWW-Authenticate headers to offer different methods. Clients choose their preferred scheme. List preferred schemes first.

Keep Learning