SubtleCrypto: exportKey() method

Baseline Widely available *

This feature is well established and works across many devices and browser versions. It’s been available across browsers since January 2020.

* Some parts of this feature may have varying levels of support.

Secure context: This feature is available only in secure contexts (HTTPS), in some or all supporting browsers.

Note: This feature is available in Web Workers.

The exportKey() method of the SubtleCrypto interface exports a key: that is, it takes as input a CryptoKey object and gives you the key in an external, portable format.

To export a key, the key must have CryptoKey.extractable set to true.

Keys can be exported in several formats: see Supported formats in the SubtleCrypto.importKey() page for details.

Keys are not exported in an encrypted format: to encrypt keys when exporting them use the SubtleCrypto.wrapKey() API instead.

Syntax

js
exportKey(format, key)

Parameters

format

A string value describing the data format in which the key should be exported. It can be one of the following:

key

The CryptoKey to export.

Return value

A Promise.

  • If format was jwk, then the promise fulfills with a JSON object containing the key.
  • Otherwise the promise fulfills with an ArrayBuffer containing the key.

Exceptions

The promise is rejected when one of the following exceptions is encountered:

InvalidAccessError DOMException

Raised when trying to export a non-extractable key.

NotSupported DOMException

Raised when trying to export in an unknown format.

TypeError

Raised when trying to use an invalid format.

Examples

Note: You can try the working examples out on GitHub.

Raw export

This example exports an AES key as an ArrayBuffer containing the bytes for the key. See the complete code on GitHub.

js
/*
Export the given key and write it into the "exported-key" space.
*/
async function exportCryptoKey(key) {
  const exported = await window.crypto.subtle.exportKey("raw", key);
  const exportedKeyBuffer = new Uint8Array(exported);

  const exportKeyOutput = document.querySelector(".exported-key");
  exportKeyOutput.textContent = `[${exportedKeyBuffer}]`;
}

/*
Generate an encrypt/decrypt secret key,
then set up an event listener on the "Export" button.
*/
window.crypto.subtle
  .generateKey(
    {
      name: "AES-GCM",
      length: 256,
    },
    true,
    ["encrypt", "decrypt"],
  )
  .then((key) => {
    const exportButton = document.querySelector(".raw");
    exportButton.addEventListener("click", () => {
      exportCryptoKey(key);
    });
  });

PKCS #8 export

This example exports an RSA private signing key as a PKCS #8 object. The exported key is then PEM-encoded. See the complete code on GitHub.

js
/*
Convert an ArrayBuffer into a string
from https://developer.chrome.com/blog/how-to-convert-arraybuffer-to-and-from-string/
*/
function ab2str(buf) {
  return String.fromCharCode.apply(null, new Uint8Array(buf));
}

/*
Export the given key and write it into the "exported-key" space.
*/
async function exportCryptoKey(key) {
  const exported = await window.crypto.subtle.exportKey("pkcs8", key);
  const exportedAsString = ab2str(exported);
  const exportedAsBase64 = window.btoa(exportedAsString);
  const pemExported = `-----BEGIN PRIVATE KEY-----\n${exportedAsBase64}\n-----END PRIVATE KEY-----`;

  const exportKeyOutput = document.querySelector(".exported-key");
  exportKeyOutput.textContent = pemExported;
}

/*
Generate a sign/verify key pair,
then set up an event listener on the "Export" button.
*/
window.crypto.subtle
  .generateKey(
    {
      name: "RSA-PSS",
      // Consider using a 4096-bit key for systems that require long-term security
      modulusLength: 2048,
      publicExponent: new Uint8Array([1, 0, 1]),
      hash: "SHA-256",
    },
    true,
    ["sign", "verify"],
  )
  .then((keyPair) => {
    const exportButton = document.querySelector(".pkcs8");
    exportButton.addEventListener("click", () => {
      exportCryptoKey(keyPair.privateKey);
    });
  });

SubjectPublicKeyInfo export

This example exports an RSA public encryption key as a PEM-encoded SubjectPublicKeyInfo object. See the complete code on GitHub.

js
/*
Convert an ArrayBuffer into a string
from https://developer.chrome.com/blog/how-to-convert-arraybuffer-to-and-from-string/
*/
function ab2str(buf) {
  return String.fromCharCode.apply(null, new Uint8Array(buf));
}

/*
Export the given key and write it into the "exported-key" space.
*/
async function exportCryptoKey(key) {
  const exported = await window.crypto.subtle.exportKey("spki", key);
  const exportedAsString = ab2str(exported);
  const exportedAsBase64 = window.btoa(exportedAsString);
  const pemExported = `-----BEGIN PUBLIC KEY-----\n${exportedAsBase64}\n-----END PUBLIC KEY-----`;

  const exportKeyOutput = document.querySelector(".exported-key");
  exportKeyOutput.textContent = pemExported;
}

/*
Generate an encrypt/decrypt key pair,
then set up an event listener on the "Export" button.
*/
window.crypto.subtle
  .generateKey(
    {
      name: "RSA-OAEP",
      // Consider using a 4096-bit key for systems that require long-term security
      modulusLength: 2048,
      publicExponent: new Uint8Array([1, 0, 1]),
      hash: "SHA-256",
    },
    true,
    ["encrypt", "decrypt"],
  )
  .then((keyPair) => {
    const exportButton = document.querySelector(".spki");
    exportButton.addEventListener("click", () => {
      exportCryptoKey(keyPair.publicKey);
    });
  });

JSON Web Key export

This example exports an ECDSA private signing key as a JSON Web Key object. See the complete code on GitHub.

js
/*
Export the given key and write it into the "exported-key" space.
*/
async function exportCryptoKey(key) {
  const exported = await window.crypto.subtle.exportKey("jwk", key);
  const exportKeyOutput = document.querySelector(".exported-key");
  exportKeyOutput.textContent = JSON.stringify(exported, null, " ");
}

/*
Generate a sign/verify key pair,
then set up an event listener on the "Export" button.
*/
window.crypto.subtle
  .generateKey(
    {
      name: "ECDSA",
      namedCurve: "P-384",
    },
    true,
    ["sign", "verify"],
  )
  .then((keyPair) => {
    const exportButton = document.querySelector(".jwk");
    exportButton.addEventListener("click", () => {
      exportCryptoKey(keyPair.privateKey);
    });
  });

Specifications

Specification
Web Cryptography Level 2
# SubtleCrypto-method-exportKey

Browser compatibility

desktop mobile server
Chrome
Edge
Firefox
Opera
Safari
Chrome Android
Firefox for Android
Opera Android
Safari on iOS
Samsung Internet
WebView Android
WebView on iOS
Bun
Deno
Node.js
exportKey
Chrome – Full support
Chrome 37 (Release date: 2014-08-26)
footnote Full support
Edge – Partial support
Edge 12 – 18 (Release date: 2015-07-29)
footnote Partial support
footnote Not supported: RSA-PSS, ECDSA, ECDH.
footnote Not supported: AES-CTR.
Edge – Full support
Edge 79 (Release date: 2020-01-15)
footnote Full support
Firefox – Full support
Firefox 34 (Release date: 2014-12-01)
footnote Full support
Opera – Full support
Opera 24 (Release date: 2014-09-02)
footnote Full support
Safari – Full support
Safari 7 (Release date: 2013-10-22)
footnote Full support
Chrome Android – Full support
Chrome Android 37 (Release date: 2014-09-03)
footnote Full support
Firefox for Android – Full support
Firefox for Android 34 (Release date: 2014-12-01)
footnote Full support
Opera Android – Full support
Opera Android 24 (Release date: 2014-09-10)
footnote Full support
Safari on iOS – Full support
Safari on iOS 7 (Release date: 2013-09-18)
footnote Full support
Samsung Internet – Full support
Samsung Internet 3 (Release date: 2015-04-10)
footnote Full support
WebView Android – Full support
WebView Android 37 (Release date: 2014-09-03)
footnote Full support
WebView on iOS – Full support
WebView on iOS 7 (Release date: 2013-09-18)
footnote Full support
Bun – Full support
Bun 1 (Release date: 2023-09-08)
footnote Full support
Deno – Partial support
Deno 1.14 – 1.14 (Release date: 2021-09-14)
footnote Partial support
footnote Not supported: ECDSA, ECDH, AES-CTR, AES-CBC, AES-GCM, AES-KW.
Deno – Partial support
Deno 1.15 – 1.17 (Release date: 2021-10-12)
footnote Partial support
footnote Not supported: ECDSA, ECDH.
Deno – Full support
Deno 1.18 (Release date: 2022-01-20)
footnote Full support
Node.js – Full support
Node.js 15 (Release date: 2020-10-20)
footnote
footnote Supports: NODE-DSA
footnote Supports: NODE-DH
footnote Supports: NODE-SCRYPT
Ed25519 algorithm
Chrome – Full support
Chrome 137 (Release date: 2025-05-27)
footnote Full support
Edge – Full support
Edge 137 (Release date: 2025-05-29)
footnote Full support
Firefox – Full support
Firefox 129 (Release date: 2024-08-06)
footnote Full support
Opera – Full support
Opera 121 (Release date: 2025-08-27)
footnote Full support
Safari – Full support
Safari 17 (Release date: 2023-09-18)
footnote Full support
Chrome Android – Full support
Chrome Android 137 (Release date: 2025-05-27)
footnote Full support
Firefox for Android – Full support
Firefox for Android 129 (Release date: 2024-08-06)
footnote Full support
Opera Android – Full support
Opera Android 90 (Release date: 2025-06-18)
footnote Full support
Safari on iOS – Full support
Safari on iOS 17 (Release date: 2023-09-18)
footnote Full support
Samsung Internet – No support
Samsung Internet
footnote No support
WebView Android – Full support
WebView Android 137 (Release date: 2025-05-27)
footnote Full support
WebView on iOS – Full support
WebView on iOS 17 (Release date: 2023-09-18)
footnote Full support
Bun – Full support
Bun 1 (Release date: 2023-09-08)
footnote Full support
Deno – Full support
Deno 1.26 (Release date: 2022-09-29)
footnote Full support
Node.js – Full support
Node.js 16.17 (Release date: 2022-08-16)
footnote Full support
X25519 algorithm
Chrome – Full support
Chrome 133 (Release date: 2025-02-04)
footnote Full support
Edge – Full support
Edge 133 (Release date: 2025-02-06)
footnote Full support
Firefox – Full support
Firefox 130 (Release date: 2024-09-03)
footnote Full support
Opera – Full support
Opera 118 (Release date: 2025-04-15)
footnote Full support
Safari – Full support
Safari 17 (Release date: 2023-09-18)
footnote Full support
Chrome Android – Full support
Chrome Android 133 (Release date: 2025-02-04)
footnote Full support
Firefox for Android – Full support
Firefox for Android 130 (Release date: 2024-09-03)
footnote Full support
Opera Android – Full support
Opera Android 88 (Release date: 2025-03-19)
footnote Full support
Safari on iOS – Full support
Safari on iOS 17 (Release date: 2023-09-18)
footnote Full support
Samsung Internet – Full support
Samsung Internet 29 (Release date: 2025-10-25)
footnote Full support
WebView Android – Full support
WebView Android 133 (Release date: 2025-02-04)
footnote Full support
WebView on iOS – Full support
WebView on iOS 17 (Release date: 2023-09-18)
footnote Full support
Bun – Full support
Bun 1.2.14 (Release date: 2025-05-21)
footnote Full support
Deno – Full support
Deno 1.26 (Release date: 2022-09-29)
footnote Full support
Node.js – Full support
Node.js 16.17 (Release date: 2022-08-16)
footnote Full support

Legend

Tip: you can click/tap on a cell for more information.

Full support
Full support
Partial support
Partial support
No support
No support
See implementation notes.
Has more compatibility info.

See also