401 Unauthorized: что означает и как исправить
401 Unauthorized означает, что в запросе отсутствуют валидные учетные данные, либо переданные учетные данные были отклонены. Сервер не говорит, что вам запрещен доступ к ресурсу, он лишь говорит, что пока не знает, кто вы, и ожидает, что вы пройдете аутентификацию, прежде чем он ответит на реальный вопрос о том, что вам разрешено делать.
Что означает 401 Unauthorized
Согласно RFC 9110, 401 - это запрос, требующий аутентификации, либо потому что она не была предоставлена, либо потому что предоставленная не прошла проверку. Ответ 401 обязан включать заголовок WWW-Authenticate, называющий схему, которую ожидает сервер, например Basic, Bearer или Digest. Этот заголовок - подсказка, которую большинство пропускает: он точно говорит, какой вид учетных данных нужен серверу, что обычно быстрее, чем гадать.
HTTP/1.1 401 Unauthorized
WWW-Authenticate: Bearer realm="api", error="invalid_token"
Как выглядит ошибка
В браузере 401, защищенный HTTP Basic-аутентификацией, вызывает нативное окно ввода имени пользователя и пароля, а не страницу, отрисованную сайтом. 401 от JSON-API, напротив, обычно виден только на вкладке сети или в тосте с ошибкой, который построило само приложение, поскольку для провала Bearer-токена нет никакого встроенного в браузер интерфейса. Из командной строки и учетные данные, и заголовок видны в одном запросе:
curl -i -H "Authorization: Bearer eyJhbGciOi..." https://api.example.com/v1/account
HTTP/1.1 401 Unauthorized
WWW-Authenticate: Bearer error="invalid_token", error_description="token is expired"
Логи сервера и приложения обычно тоже фиксируют причину, например "token expired", "signature invalid" или "no Authorization header", что сужает причину быстрее, чем один лишь общий код состояния.
Что вызывает 401 Unauthorized
Примерно в порядке того, насколько часто это оказывается причиной:
- Учетные данные вообще не были отправлены. Сессия с вышедшим пользователем, отсутствующий ключ API либо клиент, вообще никогда не прикреплявший заголовок
Authorization. - Истекший токен. Cookie сессии, токены доступа OAuth и JWT все несут срок жизни, и клиент, использующий устаревший токен, получает 401, даже если тот работал минуты назад.
- Расхождение часов между клиентом и сервером. Утверждения
expиnbfу JWT оцениваются относительно часов сервера. Сервер или клиент с неверным временем может отклонить токен, который по собственным расчетам токена все еще действителен, либо принять уже истекший. - Неверная схема аутентификации. Отправка
Authorization: Basic ...на эндпоинт, ожидающийBearer, или наоборот, проваливается, даже если заголовок присутствует. - Ключ API размещен не в том месте. Одни API ожидают ключ в пользовательском заголовке вроде
X-API-Key, другие вAuthorization, а третьи - как параметр запроса. Размещение валидного ключа не в том месте выглядит идентично отсутствию ключа вообще. - Обратный прокси или шлюз убирает заголовок Authorization. Некоторые конфигурации прокси и CDN отбрасывают заголовки, которые явно не настроены на пересылку, и совершенно валидные учетные данные никогда не доходят до origin.
- Отозванные учетные данные. Пользователь сменил пароль, администратор ротировал ключ API, либо токен был явно признан недействительным при выходе.
401 против 403
Эти два кода часто путают, поскольку оба отказывают в запросе, но спецификация проводит четкую границу. 401 означает, что серверу нужно, чтобы вы прошли аутентификацию, и валидные учетные данные могли бы изменить результат; он обязан нести WWW-Authenticate. 403 означает, что сервер точно понял, кто вы, и все равно отказывает, по причине, которую аутентификация исправить не может, например ограничение по роли или тарифу. Если повторный вход правдоподобно мог бы помочь, это должен быть 401. Если пользователь уже вошел и ему просто не разрешено, это должен быть 403, хотя на практике многие API вольно используют 401 для обоих случаев.
Как понять, кто виноват
Если вы тот, кто вызывает API, воспроизведите запрос со свежими учетными данными из чистого окружения; если только что выпущенный токен работает успешно, старый просто истек либо был отозван. Если новый токен тоже проваливается, проверьте схему и название заголовка по документации API, прежде чем предполагать, что сломан сервер. Если вы администрируете сервис, а пользователи сообщают о 401, которые вы не можете воспроизвести на своем собственном аккаунте, быстрее всего отделить "сервер в порядке, устарели отдельные токены" от "аутентификация сломана вообще для всех" - запустить HTTP-проверку с заведомо рабочими учетными данными сразу из нескольких мест и сравнить результаты.
Как исправить 401 Unauthorized
Если вы посетитель
- Войдите заново. Большинство 401 от веб-приложения - это просто истекшая сессия, и повторный вход ее обновляет.
- Проверьте системные часы на своем устройстве, если один и тот же вход постоянно проваливается сразу после аутентификации. Часы, сбитые на несколько минут, могут аннулировать основанные на времени токены у некоторых клиентов.
- Перевыпустите ключ API или токен в настройках аккаунта, если подозреваете, что он был ротирован или отозван, а не предполагайте баг в коде своей интеграции.
- Убедитесь, что заголовок Authorization действительно отправляется, используя вкладку сети в браузере либо простой вызов
curl, поскольку некоторые библиотеки HTTP-клиента молча отбрасывают пользовательские заголовки при редиректе.
Если вы администрируете сайт
- Прочитайте заголовок
WWW-Authenticateи собственные логи на предмет конкретной причины отказа, прежде чем что-либо менять; "expired", "invalid signature" и "missing header" каждый указывают на свое исправление. - Проверьте синхронизацию часов на серверах, выпускающих и проверяющих токены. Дрейф NTP на любой стороне - классическая, прерывистая причина отказов JWT, которые в остальном выглядят случайными.
- Убедитесь, что прокси или балансировщик нагрузки пересылает заголовок Authorization. Правило, добавленное по несвязанной причине, может молча убирать его для каждого запроса за этим переходом.
- Четко документируйте ожидаемую схему и название заголовка в своей документации API и возвращайте конкретный
error_descriptionв заголовкеWWW-Authenticate, чтобы интеграторам не приходилось гадать. - Различайте 401 и 403 в собственных ответах там, где это важно для вызывающих, чтобы клиентский код мог отличить "обновите токен" от "вам никогда не будет это разрешено".
Как предотвратить незаметный сбой из-за 401
401, вызванный истекшим подписывающим сертификатом, разошедшимися часами либо изменением прокси, начавшим отбрасывать заголовок Authorization, не будет выглядеть как падение. Сервис отвечает мгновенно и корректно по своим собственным правилам, так что он может оставаться сломанным для каждого вызывающего, пока кто-то не заметит. HTTP-проверка с проверкой ожидаемого кода состояния, запущенная с рабочими учетными данными против аутентифицированного эндпоинта, ловит это в момент, когда это начинает происходить. Конкретно для API сочетание этого с мониторингом API, проверяющим тела ответов, а не только коды состояния, также ловит токен, проходящий аутентификацию, но возвращающий некорректные данные.
Похожие ошибки
См. 403 Forbidden - для запросов, которые сервер понял и отклонил независимо от учетных данных, обзор 4xx - для более широкого семейства ошибок клиента, а также другие руководства из этой партии: 405 Method Not Allowed, 422 Unprocessable Content.
Часто задаваемые вопросы
Почему я получаю 401 сразу после успешного входа?
Обычно из-за несовпадения часов между вашим устройством и сервером, либо потому что клиент закэшировал старый, уже недействительный токен вместо использования только что выпущенного. Убедитесь, что системное время верно и что новый токен действительно отправляется.
Означает ли 401, что мой аккаунт взломали?
Само по себе нет. Это почти всегда означает истекшую сессию, отозванный ключ либо неправильно отправленный заголовок. Относитесь к этому как к проблеме безопасности, только если вы не ожидали, что учетные данные перестанут работать, и не можете объяснить, почему это произошло.
В чем разница между 401 и провалом аутентификации на уровне TLS?
Провал клиентского сертификата TLS вообще не дает установиться соединению, поэтому никакой код состояния HTTP не возвращается вообще. 401 означает, что соединение установилось успешно, и сервер получил полный HTTP-запрос, а затем отклонил его на уровне приложения за отсутствие валидных учетных данных.
Должна ли сама форма входа когда-либо возвращать 401?
Нет. Эндпоинт входа, оценивающий имя пользователя и пароль, не аутентифицирует существующий запрос; неверный пароль там по соглашению - это 400 либо 200 с полезной нагрузкой ошибки, поскольку весь смысл этого эндпоинта - принимать неаутентифицированные попытки и оценивать их.
Может ли валидный ключ API все равно давать 401?
Да, если он отправлен не в том заголовке или не в той схеме, если он был ротирован после того, как ваша интеграция закэшировала старый, либо если запрос дошел до сервера через прокси, убравший заголовок перед пересылкой.