Skip to main content

Documentation Index

Fetch the complete documentation index at: https://mintlify.com/tkhq/sdk/llms.txt

Use this file to discover all available pages before exploring further.

@turnkey/iframe-stamper stamps Turnkey API requests using credentials that live inside a sandboxed iframe hosted by Turnkey. The key material never leaves the iframe’s isolated execution context — your page communicates with the iframe through the browser’s MessageChannel API. This stamper is used in flows where credentials are delivered out-of-band, such as email OTP authentication, phone OTP authentication, and wallet or private key export and import.

Installation

npm install @turnkey/iframe-stamper @turnkey/http

How the iframe security model works

The iframe is served from a Turnkey-controlled origin and sandboxed with allow-scripts allow-same-origin. When the iframe initializes it generates an ephemeral P-256 key pair and sends the public key to the parent page. The parent never receives the private key. Turnkey encrypts the credential bundle (e.g., the OTP session key) to that ephemeral public key using HPKE (RFC 9180). The parent injects the encrypted bundle into the iframe via MessageChannel. The iframe decrypts it internally and uses the resulting credential to sign subsequent requests. The credential cannot be extracted by the parent page.

Auth and recovery flow

Use this flow for email OTP or phone OTP authentication.
import { IframeStamper } from "@turnkey/iframe-stamper";
import { TurnkeyClient } from "@turnkey/http";

const TurnkeyIframeContainerId = "turnkey-iframe-container";
const TurnkeyIframeElementId = "turnkey-iframe";

const iframeStamper = new IframeStamper({
  iframeUrl: process.env.AUTH_IFRAME_URL!,
  iframeContainer: document.getElementById(TurnkeyIframeContainerId),
  iframeElementId: TurnkeyIframeElementId,
});

// Insert the iframe into the DOM and obtain the iframe's ephemeral public key
const publicKey = await iframeStamper.init();

// Inject the encrypted credential bundle from Turnkey's auth response
const injected = await iframeStamper.injectCredentialBundle(credentialBundle);

// HTTP client that signs using the credential inside the iframe
const client = new TurnkeyClient(
  { baseUrl: "https://api.turnkey.com" },
  iframeStamper,
);

Wallet export flow

Use this flow to display an encrypted wallet seed phrase to the user.
const iframeStamper = new IframeStamper({
  iframeUrl: process.env.EXPORT_IFRAME_URL!,
  iframeContainer: document.getElementById("turnkey-iframe-container"),
  iframeElementId: "turnkey-iframe",
});

const publicKey = await iframeStamper.init();

// exportBundle is the response from ACTIVITY_TYPE_EXPORT_WALLET
const injected = await iframeStamper.injectWalletExportBundle(
  exportBundle,
  organizationId,
);

if (injected !== true) {
  throw new Error("unexpected error while injecting export bundle");
}

// The iframe is now displaying the seed phrase — make it visible
setIframeDisplay("block");

Wallet import flow

Use this flow to let users enter their seed phrase inside the iframe for secure import.
const iframeStamper = new IframeStamper({
  iframeUrl: process.env.IMPORT_IFRAME_URL!,
  iframeContainer: document.getElementById("turnkey-iframe-container"),
  iframeElementId: "turnkey-iframe",
});

await iframeStamper.init();

// importBundle is the response from ACTIVITY_TYPE_INIT_IMPORT_WALLET
const injected = await iframeStamper.injectImportBundle(
  importBundle,
  organizationId,
  userId,
);

if (injected !== true) {
  throw new Error("unexpected error while injecting import bundle");
}

// Show the iframe so the user can enter their seed phrase
setIframeDisplay("block");

// After the user has entered their seed phrase, extract the encrypted bundle
// to pass to ACTIVITY_TYPE_IMPORT_WALLET
const encryptedBundle = await iframeStamper.extractWalletEncryptedBundle();

IframeStamper constructor

iframeUrl
string
required
The URL of the Turnkey-hosted iframe. Use the URL provided by Turnkey for the specific flow (auth, export, or import). Available as environment variables such as AUTH_IFRAME_URL, EXPORT_IFRAME_URL, and IMPORT_IFRAME_URL.
iframeContainer
HTMLElement | null | undefined
required
The DOM element into which the iframe will be inserted. Pass a reference to the container element in your page.
iframeElementId
string
required
The id attribute to assign to the <iframe> element. Must be unique within the page. Used to look up the element and prevent duplicate insertion.
clearClipboardOnPaste
boolean
default:"true"
When true, the iframe requests clipboard-write permission so it can clear the clipboard after the user pastes a seed phrase or OTP code, reducing the risk of sensitive data remaining in the clipboard.

Methods

init(dangerouslyOverrideIframeKeyTtl?)

Inserts the iframe into the DOM, establishes a MessageChannel with the iframe, and returns a promise that resolves to the iframe’s ephemeral public key. You must call and await init() before calling any other method. The optional dangerouslyOverrideIframeKeyTtl parameter overrides the default embedded key TTL (48 hours). Only use this if you understand the security implications.

injectCredentialBundle(bundle)

Injects an encrypted credential bundle into the iframe. Used during email and phone OTP auth flows. The bundle must be encrypted to the iframe’s public key using HPKE.

injectWalletExportBundle(bundle, organizationId)

Injects an encrypted wallet export bundle. The iframe decrypts and displays the seed phrase to the user. bundle is the value from ACTIVITY_TYPE_EXPORT_WALLET.

injectKeyExportBundle(bundle, organizationId, keyFormat?, address?)

Injects an encrypted private key export bundle. keyFormat controls the encoding of the decrypted key: HEXADECIMAL, SOLANA, BITCOIN_MAINNET_WIF, BITCOIN_TESTNET_WIF, or SUI_BECH32.

injectImportBundle(bundle, organizationId, userId)

Injects an import bundle from ACTIVITY_TYPE_INIT_IMPORT_WALLET or ACTIVITY_TYPE_INIT_IMPORT_PRIVATE_KEY. Prepares the iframe to accept the user’s seed phrase.

extractWalletEncryptedBundle()

Encrypts the seed phrase the user has entered in the iframe and returns the ciphertext. Pass this value to ACTIVITY_TYPE_IMPORT_WALLET.

extractKeyEncryptedBundle(keyFormat?)

Encrypts the private key the user has entered in the iframe and returns the ciphertext. Pass this value to ACTIVITY_TYPE_IMPORT_PRIVATE_KEY.

stamp(payload)

Signs a serialized request payload using the credential currently loaded in the iframe. Called automatically by TurnkeyClient — you do not need to call this directly.

applySettings(settings)

Applies CSS styling to the text input inside the iframe. Accepts a TIframeSettings object with a styles property containing fields such as fontSize, fontFamily, color, backgroundColor, and more.

publicKey()

Returns the iframe’s current ephemeral public key, or null if init() has not been called.

clear()

Removes the iframe from the DOM and closes the MessageChannel. Call this when the flow is complete to clean up resources.

Key formats for export and import

FormatDescription
HEXADECIMAL64 hex characters. Used by MetaMask, Ledger, and Trezor for Ethereum keys
SOLANABase58-encoded secret key. Used by Phantom and Solflare
BITCOIN_MAINNET_WIFWallet Import Format for mainnet Bitcoin wallets
BITCOIN_TESTNET_WIFWallet Import Format for testnet Bitcoin wallets
SUI_BECH32Bech32 format used by Sui wallets