Сообщение об ошибке
TypeError: Failed to execute 'importKey' on 'SubtleCrypto': The provided value is not of type '(ArrayBuffer or ArrayBufferView or JsonWebKey)'.
Также выводится как
- TypeError: SubtleCrypto.importKey: Argument 2 is not an object.
- TypeError: Type error
Выше приведён текст Chromium; Firefox пишет «SubtleCrypto.importKey: Argument 2 is not an object.», Safari/WebKit — просто «Type error». Node.js на тот же вызов выдаёт `ERR_INVALID_ARG_TYPE`.
WebCrypto SubtleCrypto.importKey — PEM text passed as keyData (Chromium / Firefox / WebKit)
Что это означает
`importKey` получил строку в качестве `keyData`. WebCrypto никогда не разбирает текст: для `"spki"`, `"pkcs8"` и `"raw"` ему нужен двоичный DER (`ArrayBuffer` или типизированный массив), для `"jwk"` — объект JavaScript. Браузер отклоняет вызов ещё на этапе преобразования аргументов, не глядя ни на формат, ни на ключ, так что сам PEM может быть совершенно корректным.
Почему это происходит
Строка PEM передана напрямую
частоТекст `-----BEGIN PUBLIC KEY-----`, полученный с сервера, из файла конфигурации или из документации библиотеки JWT. Сначала его нужно декодировать из base64 в DER.
Текст Base64 вместо байтов
частоДаже без строк обрамления строка base64 остаётся строкой. Декодируйте её в байты с помощью `atob` (или `Uint8Array.fromBase64`, где он доступен).
JWK в виде текста JSON
иногдаДля формата `"jwk"` текст, полученный через `JSON.stringify`, вызывает ту же ошибку; передавайте разобранный объект.
Как исправить
- 1.
Удалите обрамление и декодируйте в байты
Удалите строки BEGIN/END и пробельные символы, декодируйте из base64 и выберите формат по метке: `PUBLIC KEY` → `spki`, `PRIVATE KEY` → `pkcs8`.
js function pemToDer(pem) { const base64 = pem.replace(/-----(BEGIN|END) [A-Z ]+-----/g, "").replace(/\s+/g, ""); return Uint8Array.from(atob(base64), (c) => c.charCodeAt(0)); } const publicKey = await crypto.subtle.importKey( "spki", pemToDer(publicKeyPem), // "PUBLIC KEY" -> spki, "PRIVATE KEY" -> pkcs8 { name: "ECDSA", namedCurve: "P-256" }, false, ["verify"], ); - 2.
Передавайте JWK как объекты
Эндпоинты JWKS и так отдают объекты; разберите текст JSON один раз и передайте объект с соответствующей кривой.
js const jwk = JSON.parse(jwkText); // an object, not the JSON string const key = await crypto.subtle.importKey("jwk", jwk, { name: "ECDSA", namedCurve: jwk.crv }, false, ["verify"]);