Сообщение об ошибке
jwt must be provided
jsonwebtoken (Node.js) — JsonWebTokenError from jwt.verify()
Что это означает
В `jwt.verify()` вообще не передан токен: первым аргументом оказались `undefined`, `null` или пустая строка. jsonwebtoken проверяет это до разбора, поэтому ни ключ, ни формат токена пока не имеют значения. Проблема возникает раньше: код, который извлекает токен из запроса, ничего не нашёл.
Почему это происходит
Клиент не отправил заголовок Authorization
частоЗапрос дошёл до маршрута без токена: пользователь не вошёл в систему, клиент забыл добавить заголовок или срок действия токена истёк на стороне клиента и токен удалили. Код вроде `req.headers.authorization.split(" ")[1]` в этом случае возвращает `undefined`.
Токен читают не из того места
частоОпечатки в именах свойств (`authorisation`, `Authorization` в объекте заголовков с именами в нижнем регистре), нестандартный заголовок вроде `x-access-token` или параметр запроса, который код не читает. Node приводит имена входящих заголовков к нижнему регистру, поэтому `req.headers.Authorization` всегда равен `undefined`.
Браузер не отправил cookie сессии
иногдаВ запросах к другому источнику cookie отправляются, только если клиент задаёт `credentials: "include"`, а cookie выставлен с атрибутами `SameSite=None; Secure`. Без middleware cookie-parser `req.cookies` тоже пуст.
Токен ещё не был готов
иногдаФронтенды, которые загружают данные до того, как процесс входа сохранит токен, или читают токен из хранилища асинхронно, отправляют первые запросы с пустым значением.
Как исправить
- 1.
Извлекайте токен с проверками и отвечайте 401
Проверяйте, есть ли токен, до вызова `verify` и возвращайте 401 с заголовком `WWW-Authenticate: Bearer`. Тогда клиенты увидят «не аутентифицирован», а не ответ 500 из-за неперехваченной ошибки.
js function bearerToken(req) { const [scheme, token] = (req.headers.authorization ?? "").split(" "); return scheme?.toLowerCase() === "bearer" && token ? token : null; } app.use((req, res, next) => { const token = bearerToken(req); if (!token) return res.status(401).set("WWW-Authenticate", "Bearer").end(); try { req.user = jwt.verify(token, publicKey, { algorithms: ["ES256"] }); next(); } catch { res.status(401).set("WWW-Authenticate", 'Bearer error="invalid_token"').end(); } }); - 2.
Добейтесь, чтобы клиент отправлял токен
Убедитесь на вкладке «Сеть» в инструментах разработчика браузера, что запрос содержит `Authorization: Bearer …` (или cookie). Если в браузере заголовок виден, а на сервере его нет, его удаляет прокси между ними.
js // Browser / Node 18+ fetch: the token must be attached explicitly. await fetch("https://api.example.com/orders", { headers: { Authorization: "Bearer " + accessToken }, }); // Cookies cross origins only with credentials and SameSite=None; Secure. await fetch("https://api.example.com/orders", { credentials: "include" });