{"record":{"id":"b4795407520f81a2","repo":"denoland/deno","slug":"unsupported-key-usage-for-an-hkdf-key","errorCode":null,"errorMessage":"Unsupported key usage for an HKDF key","messagePattern":"Unsupported key usage for an HKDF key","errorType":"exception","errorClass":"DOMException","httpStatus":null,"severity":"error","filePath":"ext/node/polyfills/internal/crypto/keys.ts","lineNumber":792,"sourceCode":"          \"SyntaxError\",\n        );\n      }\n    } else if (algName === \"HKDF\") {\n      if (extractable) {\n        throw new DOMException(\n          \"HKDF keys are not extractable\",\n          \"SyntaxError\",\n        );\n      }\n      if (\n        usages.length > 0 &&\n        ArrayPrototypeSome(\n          usages,\n          (u: string) =>\n            !ArrayPrototypeIncludes([\"deriveKey\", \"deriveBits\"], u),\n        )\n      ) {\n        throw new DOMException(\n          \"Unsupported key usage for an HKDF key\",\n          \"SyntaxError\",\n        );\n      }\n    } else if (algName === \"HMAC\") {\n      if (usages.length === 0) {\n        throw new DOMException(\n          \"Usages cannot be empty when importing a secret key.\",\n          \"SyntaxError\",\n        );\n      }\n      const alg = algorithm as { length?: number };\n      if (alg.length !== undefined && alg.length === 0) {\n        throw new DOMException(\n          \"HmacImportParams.length cannot be 0\",\n          \"DataError\",\n        );\n      }","sourceCodeStart":774,"sourceCodeEnd":810,"githubUrl":"https://github.com/denoland/deno/blob/9ad36f7a2cce60488e6ec52283efb32efddaf93a/ext/node/polyfills/internal/crypto/keys.ts#L774-L810","documentation":"Thrown by SecretKeyObject.toCryptoKey() when the algorithm is 'HKDF' and the usages array is non-empty and contains anything other than 'deriveKey' or 'deriveBits'. HKDF keys exist solely as derivation inputs in WebCrypto, so any other usage entry is rejected with a SyntaxError DOMException. As with PBKDF2, an empty usages array is accepted by this branch.","triggerScenarios":"createSecretKey(ikm).toCryptoKey('HKDF', false, ['deriveBits', 'encrypt']) — at least one usage outside ['deriveKey','deriveBits'].","commonSituations":"One generic usages array shared across HMAC, AES and HKDF imports; wrappers that copy the caller's requested operations straight through; upgrading key-derivation code from scrypt/pbkdf2 to HKDF while keeping old usages.","solutions":["Use only 'deriveKey' and/or 'deriveBits' for HKDF","Pass [] if you have no specific usage to declare","Derive with crypto.subtle.deriveBits/deriveKey and use the output key for the actual operation"],"exampleFix":"// before\nconst hkdfKey = createSecretKey(ikm).toCryptoKey('HKDF', false, ['sign']); // throws\n\n// after\nconst hkdfKey = createSecretKey(ikm).toCryptoKey('HKDF', false, ['deriveBits']);\nconst okm = await crypto.subtle.deriveBits({ name: 'HKDF', hash: 'SHA-256', salt, info }, hkdfKey, 256);","handlingStrategy":"validation","validationCode":"const ALLOWED = ['deriveKey', 'deriveBits'];\nconst usages = requestedUsages.filter((u) => ALLOWED.includes(u));\nconst key = secretKeyObject.toCryptoKey('HKDF', false, usages);","typeGuard":"const isDerivationUsage = (u: string): boolean =>\n  u === 'deriveKey' || u === 'deriveBits';","tryCatchPattern":"try {\n  key = secretKeyObject.toCryptoKey('HKDF', false, usages);\n} catch (e) {\n  if (e instanceof DOMException && e.name === 'SyntaxError' && /Unsupported key usage/.test(e.message)) {\n    key = secretKeyObject.toCryptoKey('HKDF', false, ['deriveBits']);\n  } else throw e;\n}","preventionTips":["Scope usage arrays to the algorithm being imported","Do not share one usages constant across HMAC, AES and HKDF code paths","Review WebCrypto usage tables per algorithm when adding a new algorithm"],"tags":["crypto","webcrypto","hkdf","key-usage","node-compat"],"backgroundTag":"webcrypto-invalid-key-usage","analyzedSha":"9ad36f7a2cce60488e6ec52283efb32efddaf93a","analyzedAt":"2026-08-20T13:07:44.778Z","schemaVersion":2},"datasetVersion":"2026-08-21T11:28:35.574Z"}