エラーメッセージ
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 文字列をそのまま渡している
よくあるサーバー、設定ファイル、JWT ライブラリのドキュメントから取得した `-----BEGIN PUBLIC KEY-----` のテキストです。先に base64 デコードして DER にしなければなりません。
バイト列ではなく Base64 テキストを渡している
よくあるアーマー行(BEGIN/END 行)がなくても、base64 の文字列は文字列のままです。`atob`(使える環境では `Uint8Array.fromBase64`)でデコードしてバイト列にしてください。
JSON テキストのままの JWK
ときどき形式 `"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"]);