Сообщение об ошибке
jwt malformed
Что это означает
Функция jwt.verify() из jsonwebtoken не смогла даже разобрать токен: строка не делится точками ровно на 3 сегмента. До проверки подписи дело не дошло: переданная строка по своей структуре — не JWT. (Строка, в которой 3 сегмента, но в заголовке не JSON в base64url, отклоняется на шаг позже, с ошибкой «invalid token».)
Почему это происходит
Заголовок Authorization разобран неправильно
частоЗначение заголовка Authorization — «Bearer eyJ...», а код оставил не ту половину: auth.split(" ")[0] передаёт в jwt.verify() вместо токена саму схему «Bearer», в которой вообще нет точек. Если передать всю строку «Bearer eyJhbGci...», ошибка будет другой: строка всё равно делится на 3 сегмента, и jsonwebtoken сообщает «invalid token», когда первый сегмент не декодируется.
В verify() попала не та переменная
частоТуда, где должен быть токен, попала другая строка: «undefined» или «null» после подстановки отсутствующего значения (клиент отправляет «Bearer null», потому что ничего не сохранил; опечатка в имени заголовка req.headers.authorisation; отсутствующий cookie), «[object Object]» после преобразования декодированной полезной нагрузки в строку вместо передачи исходного токена, а то и идентификатор пользователя. Настоящие undefined, null или пустая строка отсекаются на одну проверку раньше, с ошибкой «jwt must be provided».
Токен обрезан при хранении или передаче
иногдаСтолбец базы данных типа VARCHAR(255), ограничение длины строки в журнале или копирование, при котором потерялся хвост, могут обрезать токен так, что от него останется меньше 3 сегментов. Токены ES256 занимают ~200+ символов, токены RS256 гораздо длиннее.
Это вообще не JWT
иногдаНекоторые провайдеры OAuth выдают непрозрачные токены доступа (случайные строки), а не JWT. Если передать непрозрачный access_token от Google/GitHub в jwt.verify(), будет именно эта ошибка: гарантированно в формате JWT только id_token (OpenID Connect).
Как исправить
- 1.
Отрежьте префикс схемы перед проверкой
Берите из заголовка Authorization только часть с токеном и обрабатывайте отсутствие заголовка, чтобы отвечать понятным 401, а не ошибкой «jwt malformed».
js const auth = req.headers.authorization ?? ""; const [scheme, token] = auth.split(" "); if (scheme !== "Bearer" || !token) { return res.status(401).json({ error: "missing bearer token" }); } jwt.verify(token, publicKey, { algorithms: ["ES256"] }); - 2.
Запишите в журнал исходное значение и посчитайте сегменты
Одна строка в журнале покажет, с чем вы имеете дело: с префиксом, обрезанным токеном или не той переменной. В JWS ровно 3 сегмента, в JWE — 5; всё остальное — не токен.
js console.log(JSON.stringify(token).slice(0, 80)); console.log("segments:", String(token).split(".").length); // must be 3 - 3.
Проверьте, что на самом деле в токене
Вставьте строку в отладчик JWT ниже: он локально декодирует заголовок и утверждения и точно покажет, какой сегмент повреждён, — или что строка вообще не JWT.