Mensagem de erro
InvalidAccessError: Failed to execute 'exportKey' on 'SubtleCrypto': key is not extractable
Também aparece como
- InvalidAccessError: The CryptoKey is nonextractable
- InvalidAccessError: A parameter or an operation is not supported by the underlying object
O texto acima é o do Chromium; Safari/WebKit: “The CryptoKey is nonextractable”; Firefox: “A parameter or an operation is not supported by the underlying object”. Em todos os casos, trata-se de uma DOMException `InvalidAccessError`.
WebCrypto SubtleCrypto.exportKey / wrapKey — DOMException InvalidAccessError (Chromium / Firefox / WebKit)
O que significa
A chave foi criada com `extractable: false`, então o material dela nunca pode ser lido de volta — nem com `exportKey`, nem com `wrapKey`. Esse é justamente o objetivo da flag: a chave privada fica dentro da implementação criptográfica do navegador, e scripts (inclusive scripts injetados) podem usá-la, mas não roubá-la. As chaves públicas de um par gerado são sempre exportáveis; este erro diz respeito a chaves privadas e chaves secretas.
Por que acontece
A chave foi gerada como não extraível de propósito
comumBibliotecas e arquiteturas no estilo das chaves de acesso (passkeys) criam chaves vinculadas ao dispositivo dessa forma. Um recurso posterior que queira exibir a chave privada, fazer backup dela ou sincronizá-la esbarra nessa decisão.
Uma chave restaurada do IndexedDB mantém a flag
ocasionalOs objetos CryptoKey armazenados no IndexedDB voltam exatamente como foram criados; torná-los exportáveis depois é impossível.
A configuração padrão de uma biblioteca
ocasionalAlgumas bibliotecas JOSE e E2E geram chaves com `extractable: false` por padrão; as funções auxiliares de exportação delas então falham com chaves privadas.
Como corrigir
- 1.
Manter a chave privada como objeto e exportar a chave pública
Armazene as chaves não extraíveis como objetos `CryptoKey` no IndexedDB e compartilhe só a chave pública (SPKI ou JWK). Assim, a proteção que a flag oferece é preservada.
js const pair = await crypto.subtle.generateKey({ name: "ECDSA", namedCurve: "P-256" }, false, ["sign", "verify"]); // Persist the non-extractable private key as a CryptoKey object (structured clone), never as bytes: await idbPut("signing-key", pair.privateKey); // Share only the public key: const jwk = await crypto.subtle.exportKey("jwk", pair.publicKey); - 2.
Criar chaves extraíveis só quando a exportação for um requisito
Se a chave privada realmente precisar sair do navegador, gere-a como extraível e exporte-a somente encapsulada com outra chave.
js // Only if the private key must leave the browser (e.g. a user-initiated, encrypted backup): const pair = await crypto.subtle.generateKey({ name: "ECDSA", namedCurve: "P-256" }, true, ["sign", "verify"]); const wrapped = await crypto.subtle.wrapKey("pkcs8", pair.privateKey, backupKey, { name: "AES-GCM", iv });