Skip to content
ecdsa.com
WebCrypto SubtleCrypto.importKeyWebCrypto

Error message

TypeError: Failed to execute 'importKey' on 'SubtleCrypto': The provided value is not of type '(ArrayBuffer or ArrayBufferView or JsonWebKey)'.

Also printed as

  • TypeError: SubtleCrypto.importKey: Argument 2 is not an object.
  • TypeError: Type error

Chromium's text is above; Firefox says "SubtleCrypto.importKey: Argument 2 is not an object.", Safari/WebKit just "Type error". Node.js reports `ERR_INVALID_ARG_TYPE` for the same call.

WebCrypto SubtleCrypto.importKey — PEM text passed as keyData (Chromium / Firefox / WebKit)

What it means

`importKey` received a string as `keyData`. WebCrypto never parses text: for `"spki"`, `"pkcs8"` and `"raw"` it wants binary DER (an `ArrayBuffer` or typed array), for `"jwk"` a JavaScript object. The browser rejects the call during argument conversion, before looking at the format or the key — so the PEM may be perfectly valid.

Why it happens

How to fix it

  1. 1.

    Strip the armour and decode to bytes

    Remove the BEGIN/END lines and whitespace, base64-decode, and choose the format by label: `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. 2.

    Pass JWKs as objects

    JWKS endpoints already deliver objects; parse JSON text once and pass the object with the matching curve.

    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"]);

Related errors

Browse the full signature error database