← All Status Codes
401
Unauthorized
⚠️ Client Error High Risk

📖 What Is HTTP 401?

Authentication is required and has either failed or not been provided. The response must include a WWW-Authenticate header indicating the auth scheme.

🛡️ Security Implications

Brute force target. Implement rate limiting, account lockout, and CAPTCHA. Never reveal whether the username or password was incorrect.

🔍 Common Causes

Missing, expired, or invalid authentication token/credentials. Session timeout. API key not provided.

🔧 How to Fix

Provide valid credentials. Check token expiration. Implement proper session management with refresh tokens.

🖥️ How to Check

curl -I -o /dev/null -w "%{http_code}" https://example.com

HTTP 401 in depth — what you actually need to know

HTTP 401 Unauthorized signals that the request requires authentication and either no credentials were provided or the credentials provided are invalid. Despite the name "Unauthorized", 401 is specifically about authentication (identity), not authorisation (permission) — the latter is what 403 Forbidden indicates.

401 responses must include a WWW-Authenticate header indicating what authentication scheme is expected (Basic, Bearer, Digest, etc.). The client should either prompt the user for credentials (browsers do this for HTTP Basic Auth) or include credentials in the next request. Repeated 401s with the same credentials usually mean the credentials are wrong.

From a security perspective, 401 vs 404 reveals information about whether resources exist. A 401 on /admin/dashboard tells attackers "this exists but requires auth" — useful for reconnaissance. Some applications return 404 instead of 401 for protected resources to obscure their existence (the security-through-obscurity tradeoff). Authentication brute-force attacks specifically watch for 401 → non-401 transitions to identify successful guesses.

Five real-world scenarios involving HTTP 401

API authentication enforcement

APIs requiring authentication return 401 for requests without valid credentials. Clients typically retry with credentials (token, API key, OAuth bearer). Standard pattern; 401 with WWW-Authenticate header indicates what authentication is expected.

Authentication brute-force attacks

Attackers test many credential pairs against login endpoints; 401 indicates failure, redirect or 200 indicates success. Defenders look for unusual rates of 401 from single sources (IP, user agent) — indicates brute-force activity. Rate limiting + account lockout + CAPTCHA on threshold defends.

Bug bounty — testing for authentication bypass

Hunters test whether protected resources can be accessed without authentication. Common findings: API endpoints checking auth on web UI but not API, authentication checks bypassed by case-changes in URL, missing checks on subdomains. Each is a valid finding.

OAuth / OIDC flows

OAuth flows produce 401s when access tokens expire. Clients handle by refreshing tokens via refresh-token flow, then retrying original request with new access token. Standard pattern; well-implemented OAuth clients handle transparently.

Compliance — audit of authentication implementation

Compliance audits verify authentication is enforced where required. Sample tests: request protected resources without credentials (expect 401), with invalid credentials (expect 401), with valid credentials (expect 200). Document evidence for SOC 2, ISO 27001, etc.

Common mistakes & edge cases

Returning 401 vs 403 incorrectly

401 = no/invalid credentials (authentication problem). 403 = valid credentials but insufficient permission (authorisation problem). Confusing these makes debugging harder and breaks API client error handling. Use the right code for the actual condition.

Including detailed authentication errors that aid brute force

Error messages like "username valid but password wrong" tell attackers username is valid — halves the brute-force search space. Use generic "invalid credentials" regardless of which credential was wrong.

Not implementing rate limiting on authentication endpoints

Authentication endpoints without rate limits enable brute-force attacks. Implement rate limiting per source IP and per username. Add CAPTCHA after threshold. Alert on unusual authentication failure rates.

Long-lived API tokens without rotation

Static API tokens that never expire are easier to brute force or compromise via token leakage. Use short-lived tokens with refresh mechanisms (OAuth flow) or rotate static tokens regularly.

Not checking authentication on all required endpoints

Authentication enforcement must be applied consistently. Common gap: web UI requires auth but API does not (or vice versa). Subdomain might bypass main domain auth. Audit comprehensively; do not rely on framework defaults to apply everywhere.

Storing credentials in URL parameters

URLs are logged in many places (web server logs, proxy logs, browser history, referer headers). Passwords or API tokens in URLs leak via these channels. Use Authorization header or POST body for credentials; never URL parameters.

Frequently Asked Questions about HTTP 401

The request requires authentication and either no credentials were provided or the credentials are invalid. Despite the name, 401 is specifically about authentication (identity verification), not authorisation (permission). 403 Forbidden is the code for authorisation failures.
401 = not authenticated (no/invalid credentials). 403 = authenticated but not authorised for this resource. After successful login, attempting to access something your account does not have permission for produces 403, not 401.
A response header included with 401 responses indicating what authentication scheme is expected. Examples: WWW-Authenticate: Basic realm="API" for HTTP Basic Auth. WWW-Authenticate: Bearer for OAuth/JWT bearer tokens. The client uses this to know how to authenticate on the next request.
Most web frameworks have authentication middleware. Configure it to return 401 with appropriate WWW-Authenticate header for unauthenticated requests to protected resources. Examples: Django REST Framework with TokenAuthentication, Express with passport, Spring Security with HTTP Basic.
Tradeoff. 401 tells attackers "this exists, requires auth" — useful for reconnaissance. 404 tells attackers nothing useful but can confuse legitimate users (they get "not found" when really they need to authenticate). For public-facing apps, 401 is typically appropriate. For high-security internal tools, 404 reduces enumeration. Match to your threat model.
Attackers test many credential combinations against login endpoints. Each failure returns 401; success returns redirect or 200. By testing thousands of credentials, attackers find any weak ones. Defences: rate limiting, account lockout on threshold, CAPTCHA, strong password requirements, MFA.
OAuth is an authorization framework using bearer tokens (typically JWTs). When access tokens expire, the API returns 401; clients handle this by refreshing the token via the refresh-token endpoint, then retrying the original request with the new token. Standard pattern.
No — generic "invalid credentials" is more secure. Telling attackers "username valid but password wrong" reveals which usernames exist, halving brute-force search space. Same generic message for both wrong-username and wrong-password cases.
Per source IP and per username separately. Per source: N attempts per minute. Per username: M attempts per minute. After threshold: return 429 Too Many Requests, add increasing delay (exponential backoff), or lock the account temporarily. Most frameworks have rate-limiting middleware (express-rate-limit, django-ratelimit, etc.).
API clients should handle 401 by either: (1) prompting user for credentials if interactive, (2) refreshing access token if using OAuth, (3) returning auth failure to caller. Well-written clients implement automatic token refresh transparently. Poorly-written clients may silently fail or repeatedly retry without different credentials.