Сообщение об ошибке
Invalid JWK EC key
Node.js crypto — TypeError, code ERR_CRYPTO_INVALID_JWK
Что это означает
createPublicKey/createPrivateKey с format: "jwk" отклонили объект JWK: не хватает обязательных полей, координаты не декодируются или точка (x, y) на самом деле не лежит на указанной кривой. Node проверяет точку при импорте, поэтому повреждённая или усечённая координата обнаруживается здесь, а не превращается в ключ, с которым ни одна подпись не проходит проверку. Те же проверки выполняются независимо от того, откуда пришёл JWK: с эндпоинта JWKS, из файла конфигурации или из другого сервиса — ошибка указывает на сам объект, а не на способ доставки.
Почему это происходит
Координаты не в base64url
частоx/y/d в JWK должны быть в base64url без дополнения (RFC 7518). Шестнадцатеричные строки и десятичные целые числа не декодируются в 32 байта, которые ожидаются для P-256. К одному варианту Node снисходителен: стандартный base64 с + / и дополнением = импортируется без замечаний, тогда как браузеры отклоняют тот же JWK с DataError — ключ, который работает на сервере, всё равно может не сработать в клиенте.
Усечённая или повреждённая координата
частоКоордината, которая потеряла символ при передаче или в которой изменился символ, описывает другое число, и точка уходит с кривой. Классическая ошибка с ведущим нулём (кодировщик записывает 31 байт, потому что первый байт был нулевым) — единственное усечение, которое Node прощает: число не меняется, поэтому ключ импортируется. Браузеры отклоняют тот же JWK (длина в байтах «should be 32»), поэтому исправить это всё равно стоит.
crv не соответствует ключевому материалу
иногдаJWK с пометкой crv: "P-256", в котором лежат координаты secp256k1 или P-384 (после ручного редактирования или копирования из шаблона), не может описывать точку на объявленной кривой.
Как исправить
- 1.
Проверяйте структуру JWK перед импортом
Проверьте поля и длины после декодирования. Для P-256 каждая из координат x и y должна декодироваться ровно в 32 байта.
js const x = Buffer.from(jwk.x, "base64url"); const y = Buffer.from(jwk.y, "base64url"); console.log(jwk.kty, jwk.crv, x.length, y.length); // EC P-256 32 32 - 2.
Дополняйте короткие координаты нулями слева
Если источник отбросил ведущие нули, восстановите фиксированную длину до того, как собирать JWK.
js const pad32 = (b) => Buffer.concat([Buffer.alloc(32 - b.length), b]); jwk.x = pad32(Buffer.from(jwk.x, "base64url")).toString("base64url"); jwk.y = pad32(Buffer.from(jwk.y, "base64url")).toString("base64url"); const key = crypto.createPublicKey({ key: jwk, format: "jwk" }); - 3.
Заново получите ключ из доверенного источника
Если координаты не проходят проверку и вы не собирали JWK сами, не чините байты, а заново загрузите его с эндпоинта JWKS издателя: JWK, который приходится латать вручную, доверия не заслуживает.