Introducing Highlights: the context that matters

HTTP 401 Unauthorized: What It Means and How to Fix It

HTTP 401 Unauthorized is a status code meaning the request lacks valid authentication credentials for the resource. Despite the name, it is about authentication, not permission: the server does not know who you are. RFC 9110 requires a 401 response to include a WWW-Authenticate header that tells the client how to authenticate.

Code
401
Name
Unauthorized
Class
4xx client error
Retry?
No, fix the cause first

What causes a 401 error?

  • →No Authorization header, or an API key sent in the wrong header or query parameter.
  • →An expired access token or session cookie.
  • →A typo, revoked key, or key from the wrong environment (test versus live).
  • →A proxy or redirect that strips the Authorization header before it reaches the server.

How do you fix a 401 error when web scraping?

  • →Check the WWW-Authenticate header in the response. It names the scheme the server expects, such as Bearer or Basic.
  • →Refresh tokens before they expire instead of waiting for the 401, and retry once after a refresh, not in a loop.
  • →If a public page suddenly answers 401, the content moved behind a login. Scraping it now needs an account you are entitled to use and the site’s terms allow, or an official API.
  • →Do not send credentials to a different host after a redirect. Most HTTP clients drop the header on cross-origin redirects for this reason.

How do you fix a 401 error on your own server?

  • →Always send WWW-Authenticate with a 401, as RFC 9110 requires.
  • →Return 401 for missing or invalid credentials and 403 for valid credentials without permission. Mixing them makes client errors hard to debug.
  • →Include a machine-readable error code in the body so clients can tell an expired token from a revoked one.

How do you handle a 401 error in a retry loop?

401 is not in RETRYABLE, so raise_for_status() raises on the first response instead of spending retries on a request that will fail the same way. Fix the cause, then send the request again.

import random
import time

import requests

RETRYABLE = {408, 429, 500, 502, 503, 504, 520, 521, 522, 523, 524}


def fetch(url: str, max_attempts: int = 5) -> requests.Response:
    for attempt in range(max_attempts):
        try:
            response = requests.get(url, timeout=(10, 60))
        except requests.Timeout:
            time.sleep(2**attempt + random.uniform(0, 1))
            continue
        if response.status_code not in RETRYABLE:
            response.raise_for_status()
            return response
        retry_after = response.headers.get("Retry-After", "")
        backoff = 2**attempt + random.uniform(0, 1)
        time.sleep(min(int(retry_after) if retry_after.isdigit() else backoff, 60))
    raise RuntimeError(f"Gave up on {url} after {max_attempts} attempts")

How does Context.dev handle a 401 error?

The Context.dev API returns 401 when the API key is missing, invalid, or disabled, and also when the organization does not have enough credits for the request. Check the message in the body to tell the two apart. Scrape itself fetches public pages, so a target that answers 401 needs credentials you are entitled to send.

See what the web scraping API does on every request, or read how to fix HTTP errors in web scraping for a longer walkthrough.

Frequently asked questions about a 401 error

What is the difference between 401 and 403?

A 401 means the server does not know who you are, so authenticating may fix it. A 403 means it knows, or does not care, and still refuses. New credentials rarely fix a 403.

Why do I get a 401 with a valid API key?

Common causes are sending the key in the wrong header, a missing Bearer prefix, a key from another environment, or a proxy that strips the header. Some APIs, Context.dev included, also return 401 when the account is out of credits.

Should I retry a 401?

Only once, after refreshing the token or fixing the credentials. Retrying the same credentials in a loop can trigger brute-force protection and lock the account.

Which status codes are related to 401?

Sources

Last reviewed

Ship an agent that actually knows things.

Free tier, 10-minute integration, and the same API powering agents at Mintlify, daily.dev, and Propane. No credit card to start.