Error message
TypeError: Failed to execute 'sign' on 'SubtleCrypto': EcdsaParams: hash: Missing or not an AlgorithmIdentifier
Also printed as
- TypeError: Failed to execute 'verify' on 'SubtleCrypto': EcdsaParams: hash: Missing or not an AlgorithmIdentifier
- TypeError: Member EcdsaParams.hash is required and must be an instance of (object or DOMString)
- NotSupportedError: Failed to execute 'sign' on 'SubtleCrypto': EcdsaParams: hash: Algorithm: Unrecognized name
Chromium's text is above (for `verify` the method name changes); Safari/WebKit: "Member EcdsaParams.hash is required and must be an instance of (object or DOMString)"; Firefox reports a generic `SyntaxError` ("An invalid or illegal string was specified").
WebCrypto SubtleCrypto.sign / verify with ECDSA — algorithm parameter without hash (Chromium / WebKit)
What it means
ECDSA in WebCrypto takes the hash function per operation, not per key: `sign` and `verify` need `{ name: "ECDSA", hash: "SHA-256" }`. The call passed an algorithm object without `hash` — usually the `{ name, namedCurve }` object from key generation — so the browser rejected the parameters before signing. (RSA keys are the opposite: their hash is fixed at import time.) A misspelled hash such as `"SHA256"` fails with a `NotSupportedError` about an unrecognized name instead.
Why it happens
The key-generation parameters reused for sign/verify
commonStoring one `ALG = { name: "ECDSA", namedCurve: "P-256" }` constant and passing it everywhere works for `generateKey` and `importKey`, but `sign` needs `hash`.
Hash name spelled the JOSE or OpenSSL way
commonWebCrypto names are `SHA-256`, `SHA-384`, `SHA-512` (with the hyphen). `SHA256`, `sha256` with no hyphen or `ES256` are unrecognized.
Expecting the key to carry the hash
occasionalCode ported from RSA (`RSASSA-PKCS1-v1_5` keys have `hash` in their import parameters) assumes ECDSA keys do too; they do not.
How to fix it
- 1.
Keep key parameters and operation parameters separate
Define one object for key creation and one for signing. For JWT ES256/ES384/ES512, use SHA-256/384/512 with P-256/384/521 respectively.
js const KEY_ALG = { name: "ECDSA", namedCurve: "P-256" }; // generateKey / importKey const SIGN_ALG = { name: "ECDSA", hash: "SHA-256" }; // sign / verify (ES256) const pair = await crypto.subtle.generateKey(KEY_ALG, false, ["sign", "verify"]); const signature = await crypto.subtle.sign(SIGN_ALG, pair.privateKey, data); // 64 bytes, raw r||s const ok = await crypto.subtle.verify(SIGN_ALG, pair.publicKey, signature, data);