Сообщение об ошибке
UnauthorizedError: No authorization token was found
Также выводится как
- No authorization token was found
- Format is Authorization: Bearer [token]
Если ошибку не обработать, Express выводит её вместе со стеком, начиная со строки «UnauthorizedError: No authorization token was found». `err.code` отличает `credentials_required` (токена нет) от `credentials_bad_scheme` и `credentials_bad_format` («Format is Authorization: Bearer [token]»).
express-jwt (Node.js) — UnauthorizedError, code credentials_required
Что это означает
express-jwt защищает маршрут, но не нашёл токен: в запросе нет заголовка `Authorization`, и пользовательская функция `getToken` тоже ничего не вернула. Поскольку `credentialsRequired` по умолчанию равен `true`, middleware выбрасывает `UnauthorizedError` с `code: "credentials_required"` и `status: 401`, и запрос так и не доходит до вашего обработчика. Если заголовок есть, но не имеет вида `Bearer <token>`, ошибка будет другой: «Format is Authorization: Bearer [token]».
Почему это происходит
Клиент не отправил заголовок Authorization
частоПользователь ещё не вошёл, HTTP-клиент без перехватчика, который добавляет заголовок, или токен удалили после истечения срока действия. Проверьте запрос на панели «Сеть» в браузере.
Токен передаётся в cookie или строке запроса
частоПо умолчанию express-jwt читает только `Authorization: Bearer`. Для токенов в cookie с флагом HttpOnly, в параметре `?access_token=` или в собственном заголовке нужна функция `getToken`, а для cookie — ещё и `cookie-parser`.
Прокси удалил заголовок
иногдаAPI-шлюзы с явным сопоставлением заголовков, прокси, которые пропускают только заголовки из списка разрешённых, или правило перезаписи, очищающее заголовок, могут отбросить `Authorization` до того, как запрос дойдёт до Node. Браузер показывает заголовок, но сервер его так и не получает.
Middleware защищает и публичные маршруты
иногда`app.use(expressjwt(...))` перед объявлением маршрутов защищает всё, включая проверки состояния, вход и статические файлы. Запросы к этим маршрутам вполне законно приходят без токена.
Как исправить
- 1.
Укажите express-jwt, где искать токен
`getToken` получает запрос и возвращает строку токена или `null`. Делайте её простой и не принимайте токены сразу из нескольких мест.
js import cookieParser from "cookie-parser"; import { expressjwt } from "express-jwt"; app.use(cookieParser()); app.use( expressjwt({ secret: getSigningKey, // e.g. jwks-rsa's expressJwtSecret(...) algorithms: ["RS256"], getToken: (req) => req.cookies.access_token ?? null, }), ); - 2.
Исключите публичные маршруты или сделайте аутентификацию необязательной
`.unless()` пропускает перечисленные пути. `credentialsRequired: false` пропускает запросы без токена, не заполняя `req.auth`, и каждый маршрут решает сам.
js app.use( expressjwt({ secret, algorithms: ["HS256"] }).unless({ path: ["/health", "/login", /^\/public\//] }), ); // Or keep authentication optional and decide per route: app.use(expressjwt({ secret, algorithms: ["HS256"], credentialsRequired: false })); - 3.
Превратите ошибку в корректный ответ 401
Обработчик Express по умолчанию берёт `status` ошибки (401), но отвечает HTML-страницей (в режиме разработки — с трассировкой стека) и без заголовка `WWW-Authenticate`. Сами преобразуйте `UnauthorizedError` в ответ 401 в формате JSON с этим заголовком.
js app.use((err, req, res, next) => { if (err.name === "UnauthorizedError") { return res.status(401).set("WWW-Authenticate", "Bearer").json({ error: err.code }); } next(err); });