HTTP 401 Unauthorized

The server requires authentication to access this resource, and your request either did not include credentials or the credentials you provided are invalid. You need to authenticate with valid credentials before the server will grant access.

What Is HTTP 401 Unauthorized?

HTTP 401 Unauthorized is a client error status code indicating that the request lacks valid authentication credentials for the target resource. Despite its name containing "Unauthorized," this status code is actually about authentication, not authorization. The server is saying "I do not know who you are" rather than "I know who you are but you are not allowed." The distinction between authentication (who are you?) and authorization (what can you do?) is an important concept that HTTP 401 and 403 address separately.

When a server returns 401, it must include a WWW-Authenticate header that describes the authentication scheme the client should use. Common schemes include Bearer for JWT and OAuth tokens, Basic for username and password credentials, and API-Key for key-based authentication. This header helps clients understand what type of credentials they need to provide in order to access the resource.

In modern web development, 401 errors are most commonly triggered by expired JWT tokens, missing API keys, revoked OAuth access tokens, or malformed Authorization headers. Understanding the difference between 401 and 403 is critical for building secure APIs. A 401 response invites the client to authenticate, while a 403 tells an authenticated client that they simply do not have permission, and re-authenticating will not help. Properly distinguishing these codes makes your API self-documenting and easier to integrate.

Common Causes

Missing Authorization Header

The request does not include an Authorization header. The API requires a Bearer token, API key, or Basic auth credentials that were not sent with the request.

Expired Access Token

The JWT or OAuth access token included in the request has expired. Tokens typically have a limited lifetime, and the server rejects expired tokens with a 401 response.

Invalid API Key

The API key in the request is incorrect, revoked, or belongs to a different environment. Development and production environments often use separate API keys.

Malformed Token Format

The Authorization header is present but formatted incorrectly. For example, missing the Bearer prefix before the token, or including extra whitespace characters.

How to Fix

Add Authentication Credentials

Include the required Authorization header in your request. For Bearer tokens, use the format Authorization: Bearer <token>. For Basic auth, use Authorization: Basic <base64-encoded-credentials>.

Refresh Expired Tokens

If using JWT or OAuth, implement token refresh logic. When you receive a 401, use the refresh token to obtain a new access token and retry the original request automatically.

Verify API Key Environment

Ensure you are using the correct API key for your environment. Production, staging, and development environments typically have separate keys that are not interchangeable.

Check Token Format

Verify the Authorization header format matches the API requirements. Use the JWT Decoder to inspect your token structure, expiration time, and claims.

Code Examples

Express.js

// Express.js — JWT authentication middleware
const express = require('express');
const jwt = require('jsonwebtoken');
const app = express();

function authenticate(req, res, next) {
  const authHeader = req.headers.authorization;

  if (!authHeader) {
    return res.status(401).json({
      error: 'Unauthorized',
      message: 'Authorization header is required'
    });
  }

  const [scheme, token] = authHeader.split(' ');

  if (scheme !== 'Bearer' || !token) {
    return res.status(401).json({
      error: 'Unauthorized',
      message: 'Invalid authorization format. Use: Bearer <token>'
    });
  }

  try {
    const decoded = jwt.verify(token, process.env.JWT_SECRET);
    req.user = decoded;
    next();
  } catch (err) {
    const message = err.name === 'TokenExpiredError'
      ? 'Token has expired' : 'Invalid token';
    return res.status(401).json({ error: 'Unauthorized', message });
  }
}

app.get('/api/profile', authenticate, (req, res) => {
  res.json({ userId: req.user.id, email: req.user.email });
});

Flask (Python)

# Flask — JWT authentication decorator
from flask import Flask, jsonify, request
from functools import wraps
import jwt
import os

app = Flask(__name__)

def require_auth(f):
    @wraps(f)
    def decorated(*args, **kwargs):
        auth_header = request.headers.get('Authorization')

        if not auth_header:
            return jsonify(
                error='Unauthorized',
                message='Authorization header is required'
            ), 401

        parts = auth_header.split()
        if len(parts) != 2 or parts[0] != 'Bearer':
            return jsonify(
                error='Unauthorized',
                message='Invalid format. Use: Bearer <token>'
            ), 401

        try:
            payload = jwt.decode(
                parts[1],
                os.environ['JWT_SECRET'],
                algorithms=['HS256']
            )
            request.user = payload
        except jwt.ExpiredSignatureError:
            return jsonify(error='Unauthorized', message='Token expired'), 401
        except jwt.InvalidTokenError:
            return jsonify(error='Unauthorized', message='Invalid token'), 401

        return f(*args, **kwargs)
    return decorated

@app.route('/api/profile', methods=['GET'])
@require_auth
def get_profile():
    return jsonify(user_id=request.user['id'], email=request.user['email'])

Frequently Asked Questions

What is the difference between 401 and 403?

HTTP 401 means the client is not authenticated. The server does not know who you are. HTTP 403 means the client is authenticated but does not have permission to access the resource. Re-authenticating will fix a 401 but not a 403.

Why is 401 called Unauthorized instead of Unauthenticated?

This is a well-known misnomer in the HTTP specification. HTTP 401 is actually about authentication, not authorization. The naming is confusing but has been in the spec since HTTP/1.0 and cannot be changed for backward compatibility.

How do I handle expired JWT tokens?

Implement a token refresh flow. When you receive a 401, check if you have a refresh token. If so, call the token refresh endpoint to get a new access token and retry the original request. If the refresh also fails, redirect the user to the login page.

Should I return 401 or 403 for an invalid API key?

Return 401 for an invalid, expired, or missing API key because the client has not authenticated successfully. Return 403 when the API key is valid but does not have permission for the specific resource or action.

Can a 401 response include a body?

Yes. Include an error message in the body explaining why authentication failed, such as missing header, expired token, or invalid credentials. Also include the WWW-Authenticate header to indicate the expected authentication scheme.

Monitor Your APIs & Services

Get instant alerts when your endpoints go down. 60-second checks, free forever.

Start Monitoring Free →