Сообщение об ошибке
Invalid Compact JWS
jose (JavaScript) — JWSInvalid, code ERR_JWS_INVALID
Что это означает
jose не удалось разделить входные данные на три разделённых точками сегмента компактной сериализации JWS: заголовок, полезную нагрузку и подпись (header.payload.signature). По структуре переданная строка — вовсе не подписанный токен; никаких криптографических операций не выполнялось. В jose это аналог ошибки «jwt malformed» из jsonwebtoken, и, как и она, эта ошибка означает, что проблема возникла ещё до библиотеки JWT: в том, что создало или передало строку.
Почему это происходит
Токен обрезан или склеен с другим
частоУ значения, потерявшего последний сегмент (столбец базы данных, строка лога, неполная копия), или у двух токенов, склеенных в одном заголовке, уже не ровно три сегмента. Префикс «Bearer » или кавычки JSON вокруг целого токена это сообщение не вызывают: в строке по-прежнему три сегмента, и jose вместо этого выдаёт «JWS Protected Header is invalid»; перевод строки в конце допускается.
В переменной нет токена
частоundefined, приведённый к строке «undefined», пустая строка из-за отсутствующего cookie или непрозрачный (не JWT) токен доступа OAuth — ни у одного из них нет структуры JWS. Сбой возникает ещё до jose.
JWE передан в API для JWS
иногдаУ зашифрованных токенов (JWE) пять сегментов, а не три. Если издатель шифрует токены, jwtVerify/compactVerify отклонят их на этом шаге; правильная точка входа — расшифрование (jwtDecrypt), а после него, если есть вложенный JWS, его проверка.
Как исправить
- 1.
Очистите входные данные и проверьте число сегментов
Перед вызовом jose обрежьте пробелы, уберите схему авторизации и проверьте число сегментов — так вы получите точные ошибки на уровне приложения вместо общей ошибки разбора.
js const token = raw.replace(/^Bearer\s+/i, "").trim(); const segments = token.split(".").length; if (segments !== 3) throw new Error(`expected JWS (3 segments), got ${segments}`); - 2.
Отправляйте токены JWE на расшифрование
Если сегментов пять, токен зашифрован. Используйте jwtDecrypt с закрытым ключом получателя вместо jwtVerify.
js import { jwtDecrypt } from "jose"; const { payload } = await jwtDecrypt(token, privateKey); // 5-segment JWE - 3.
Проследите, где формируется строка
Если очищенное значение всё равно не проходит, записывайте в лог его длину и первые символы на каждом звене: клиенте, шлюзе, хранилище, обработчике. Первый сегмент подписанного JWT — это JSON в base64url, поэтому настоящие токены начинаются с «eyJ» (результат кодирования '{"'); звено, на котором это перестаёт выполняться, и есть место повреждения.
js console.log(token.length, JSON.stringify(token.slice(0, 12))); // healthy: 300+ 'eyJhbGciOiJF'