HTTP 401 Unauthorized¶
HTTP 401 Unauthorized — код состояния HTTP, указывающий, что запрос не был аутентифицирован: клиент не предоставил учётные данные (или предоставил неверные), необходимые для доступа к запрашиваемому ресурсу. Код 401 входит в категорию клиентских ошибок (4xx) и означает, что сервер понял запрос, но отказывается его выполнять до тех пор, пока клиент не представит подтверждённой личности. Стандарт определён в документе RFC 9110 (ранее — RFC 7231), который описывает семантику HTTP-методов и кодов состояния.
¶Семантика и отличие от 403
Ключевое отличие 401 от близкого кода 403 Forbidden заключается в том, что 401 подразумевает: аутентификация возможна и может привести к успеху, если клиент повторит запрос с корректными учётными данными. Код 403 означает, что сервер понял личность запросившего, но доступ всё равно запрещён — повторная аутентификация ситуацию не изменит.
Согласно спецификации, ответ 401 обязан содержать заголовок WWW-Authenticate с указанием схемы аутентификации (Basic, Bearer, Digest и др.), которую сервер ожидает от клиента. На практике многие веб-серверы и API-платформы отдают 401 и без этого заголовка, что формально нарушает RFC, но широко распространено.
¶Типичные причины возникновения
- Отсутствие заголовка
Authorizationв запросе к защищённому ресурсу. - Истёкший срок действия токена доступа (например, JWT).
- Неверный логин или пароль при Basic-аутентификации.
- Некорректный формат токена (отсутствует схема
Bearer, опечатка в значении). - Отсутствие cookie сессии или её истечение.
¶Формат ответа
Пример типичного ответа сервера:
``` HTTP/1.1 401 Unauthorized WWW-Authenticate: Bearer realm="example" Content-Type: application/json
{"error": "unauthorized", "message": "Token expired"} ```
Тело ответа не нормализовано стандартом: сервер может вернуть HTML-страницу, JSON-объект или пустое тело. Многие фреймворки (Spring Security, Django REST Framework, Express с Passport.js) формируют собственный формат ошибки.
¶Обработка на клиенте
Браузеры при получении 401 с заголовком WWW-Authenticate: Basic показывают системное окно ввода логина и пароля. Для схем Bearer и Digest поведение зависит от браузера и контекста.
При работе с API стандартный паттерн — перехватить 401 и попытаться обновить токен через refresh-токен, после чего повторить исходный запрос. Если обновление невозможно, клиент считается неаутентифицированным и перенаправляется на страницу входа.
¶Отличие от смежных кодов
| Код | Название | Значение |
|---|---|---|
| 401 | Unauthorized | Нет аутентификации; повтор с учётными данными имеет смысл |
| 403 | Forbidden | Аутентификация не поможет; доступ запрещён |
| 407 | Proxy Authentication Required | Требуется аутентификация перед прокси-сервером |
| 440 | Login Timeout (IIS) | Сессия входа истекла (нет в стандарте, используется Microsoft IIS) |
| 498 | Invalid Token (устаревший) | Некорректный токен; использовался некоторыми API, в RFC не входит |
¶Безопасность
Ответ 401 не должен раскрывать, существует ли запрашиваемый ресурс или какая именно часть учётных данных неверна — иначе возможна атака перебором (brute force) с разведкой валидных логинов. Рекомендовано использовать единообразные сообщения вида «неверные учётные данные».
Частая ошибка разработчиков — возвращать 200 OK с JSON вида {"error": "unauthorized"} вместо 401. Это ломает стандартную обработку в HTTP-клиентах, прокси и браузерах.
¶401 в российских реалиях
В российской веб-разработке код 401 широко используется в государственных информационных системах, интегрированных с ЕСИА (Единой системой идентификации и аутентификации). При обращении к порталу Госуслуг и связанным с ним сервисам пользователь проходит аутентификацию через ЕСИА, после чего клиентское приложение получает токен доступа; истечение токена приводит к ответу 401 и необходимости повторного входа. Стандарты взаимодействия с ЕСИА описаны в открытых документации регулятора и используют OAuth 2.0 с грантами, адаптированными под российские требования к аутентификации.
¶Историческая справка
Код 401 появился в первой версии спецификации HTTP (HTTP/0.9 не имел кодов состояния, HTTP/1.0, 1996) и был описан в RFC 1945, затем в RFC 2616 (1999) и пересмотрен в RFC 7235 (2014). В актуальной редакции RFC 9110 (2022) семантика кода сохранена без существенных изменений.
