WWW-Authenticate header: Basic auth in nginx, Bearer, and why the login prompt doesn't appear (tested)

A 401 response should say how to authenticate in WWW-Authenticate. We protected a folder with nginx auth_basic and logged what curl and Chrome did with each answer.

1. What nginx auth_basic answered

RequestStatusResponse header / error log
No credentials401WWW-Authenticate: Basic realm="Staging area"
curl -u alice:s3cret200page served
Wrong password (or wrong case)401log: user "alice": password mismatch
Unknown user401log: user "bob" was not found in "/etc/nginx/htpasswd"
Authorization: Bearer abc401Basic challenge again: nginx only understands Basic
Password file missing403log: open() "/etc/nginx/nope" failed
location /staging/ {
    auth_basic           "Staging area";   # becomes realm="Staging area"
    auth_basic_user_file /etc/nginx/htpasswd;
}
location /staging/health { auth_basic off; }   # public exception

Log lines tell you which case you're in; the client always sees the same 401.

2. The trap: return skips auth_basic

With return 200 "..."; in the protected location, every request got 200 without credentials, no 401 at all. return runs in nginx's rewrite phase, before the access phase where auth_basic checks the password. Protect locations that serve files or proxy_pass; don't test your setup with a return stub.

3. Basic vs Bearer, and when the browser asks

Basic sends the password base64-encoded, not encrypted: use it only over HTTPS (HSTS in nginx). Inspect what a URL sends with the free HTTP headers checker.

Frequently asked questions

What does WWW-Authenticate: Basic realm mean?

The server wants a username and password (HTTP Basic). The realm is the label from nginx's auth_basic, e.g. auth_basic "Staging area" sent realm="Staging area" in our test.

Why is nginx auth_basic not working?

In our test a location using return 200 served every request without asking for a password, because return runs before auth_basic. Also check the error log: a missing password file gave 403, not 401.

Why doesn't the browser show a login prompt on 401?

The response needs WWW-Authenticate: Basic. With no WWW-Authenticate header, or a Bearer challenge, Chrome sent no credentials in our test.

Can nginx auth_basic check a Bearer token?

No. A Bearer Authorization header got the Basic 401 challenge back; token checks need your app (or nginx auth_request, per the nginx docs).

What's the difference between 401 and 403 here?

401 + WWW-Authenticate means 'send credentials'. nginx answered 403 when the password file couldn't be opened.

Written with AI assistance. Measured on 2026-10-01 with a throwaway nginx:alpine container (auth_basic + auth_basic_user_file, removed afterwards), curl, and Chromium 153 (full build) with Playwright httpCredentials against nginx and a small Node server that answered 401 with no WWW-Authenticate or with a Bearer challenge. Password hashing advice (htpasswd -B / bcrypt) is from the nginx docs, not this test; the test file used a {PLAIN} entry. PlainHeaders is our extension; the other methods are free.