Сообщение об ошибке
secretOrPublicKey must be an asymmetric key when using ES256
Что это означает
Вы попросили jsonwebtoken проверить (или подписать: в парном сообщении вместо этого стоит secretOrPrivateKey) токен ES256, но передали симметричный секрет — обычную строку или Buffer, а не PEM и не KeyObject. ES256 — это ECDSA на кривой P-256: для него нужна пара ключей EC, а не общий секрет.
Почему это происходит
В конфигурации остался секрет со времён HMAC
частоСервис использовал HS256 с общим секретом, кто-то переключил alg на ES256, а в JWT_SECRET по-прежнему лежит «supersecret». Случайная строка — не ключ EC, и jsonwebtoken отказывается делать вид, что это ключ.
Подключена не та переменная конфигурации
частоPEM есть, но код читает переменную, в которой лежит что-то другое — идентификатор ключа или URL JWKS (https://issuer/.well-known/jwks.json — это строка, а не ключ). Пустая переменная даёт другую ошибку: «secret or public key must be provided».
PEM повредился по пути через конфигурацию
частоPEM, который приходит с буквальными последовательностями \n, в кавычках или с отступами из YAML-файла, больше не разбирается как ключ, поэтому jsonwebtoken 9 считает строку общим секретом и выдаёт эту ошибку. Перед передачей восстановите переводы строк и уберите кавычки.
Передан JWK там, где ожидается PEM/KeyObject
иногдаJWK — это JSON-объект; если преобразовать его в строку и передать в jwt.verify(), получится строка, а не PEM и не KeyObject. Сначала его нужно преобразовать (crypto.createPublicKey({ key: jwk, format: "jwk" })).
Как исправить
- 1.
Загрузите настоящий открытый ключ EC
Проверяйте ES256 с помощью PEM (SPKI) или KeyObject. Если у вас JWK (например, из эндпоинта JWKS), сначала преобразуйте его с помощью node:crypto.
js import { createPublicKey } from "node:crypto"; const key = createPublicKey({ key: jwk, format: "jwk" }); // or a PEM string jwt.verify(token, key, { algorithms: ["ES256"] }); - 2.
Получайте ключи JWKS через вспомогательную функцию
Если издатель публикует ключи по URL JWKS, не передавайте этот URL в качестве ключа — получайте ключ для каждого токена по kid.
js import { createRemoteJWKSet, jwtVerify } from "jose"; const jwks = createRemoteJWKSet(new URL("https://issuer.example/.well-known/jwks.json")); const { payload } = await jwtVerify(token, jwks, { algorithms: ["ES256"] }); - 3.
Или вам на самом деле нужен HS256
Если и издатель, и проверяющая сторона — ваш собственный сервис и общий секрет используется намеренно, задайте algorithm: "HS256" на обеих сторонах вместо ES256. Именно смешивание этих двух семейств и предотвращает эта ошибка, в том числе классический сценарий атаки с подменой типа ключа.