API keys
To create a valid, API key stamped request follow these steps:1
Sign the JSON-encoded POST body with your API key to produce a
signature (DER-encoded)2
Hex encode the
signature3
Create a JSON-encoded stamp:
publicKey: the public key of the API key. Turnkey supports multiple API key curves:API_KEY_CURVE_P256, API_KEY_CURVE_SECP256K1, API_KEY_CURVE_ED25519signature: the signature produced by the API keyscheme: the signature scheme used to sign the request, matching the curve of thepublicKey. The supported schemes are:SIGNATURE_SCHEME_TK_API_P256, SIGNATURE_SCHEME_TK_API_SECP256K1, SIGNATURE_SCHEME_TK_API_ED25519, SIGNATURE_SCHEME_TK_API_SECP256K1_EIP191
4
Base64URL encode the stamp
5
Attach the encoded string to your request as a
X-Stamp header6
Submit the stamped request to Turnkey’s API
WebAuthn
To create a valid, WebAuthn authenticator stamped request follow these steps:1
Compute the WebAuthn challenge by hashing the POST body bytes (JSON encoded) with SHA256. For example, if the POST body is
{"organization_id": "1234", "type": "ACTIVITY_TYPE_CREATE_API_KEYS", "params": {"for": "example"}}, the WebAuthn challenge is the string 7e8b4653fc7e51dc119cea031942f4693b4742ceca4dda269b925802b38b21472
Include the challenge amongst WebAuthn signing options. Refer to the existing stamper implementations in the following section for examples
- Note that if you need to pass the challenge as bytes, you’ll need to utf8-encode the challenge string (in JS, the challenge bytes will be
TextEncoder().encode("7e8b4653fc7e51dc119cea031942f4693b4742ceca4dda269b925802b38b2147")) - Additional note for React Native contexts: the resulting string should then additionally be base64-encoded. See implementation
3
Create a JSON-encoded stamp:
credentialId: the id of the WebAuthn authenticatorauthenticatorData: the authenticator data produced by the WebAuthn assertionclientDataJson: the client data produced by the WebAuthn assertionsignature: the signature produced by the WebAuthn assertion
4
Attach the JSON-encoded stamp to your request as a
X-Stamp-Webauthn header-
Header names are case-insensitive (so
X-Stamp-WebauthnandX-Stamp-WebAuthnare considered equivalent) -
Unlike API key stamps, the format is just JSON; no base64URL encoding necessary! For example:
X-Stamp-Webauthn: {"authenticatorData":"UaQZ...","clientDataJson":"eyJ0...","credentialId":"Grf...","signature":"MEQ..."}
Attested
Attested stamps allow authenticators that cannot directly sign requests (Email OTP, SMS OTP, and OAuth) to prove identity. Instead of the public key itself being a stored credential, the public key is attested by a token that proves ownership of an identity (an email address, phone number, or OAuth provider). To create a valid attested stamp:1
Generate a P256 key pair on the client
2
Obtain a token that attests this key pair belongs to the identity. The token must contain the client public key, cryptographically binding the key to the identity:
- For Email OTP / SMS OTP: a
verificationTokenissued by Turnkey after a successful OTP verification. The token embeds the clientpublic_keyalongside the contact (email or phone). - For OAuth: an
oidcTokenfrom the OAuth provider (e.g., Google). The token’snoncemust be set to the hash of the client public key.
3
Sign the JSON-encoded POST body with the client private key to produce a
signature4
Create a JSON-encoded stamp:
publicKey: the client public key (hex-encoded)signature: the signature over the request body (hex-encoded)publicKeyAttestation: the token (verification token or OIDC token) that ties the public key to the identityscheme: the attestation scheme.STAMP_ATTESTED_SCHEME_P256_VERIFICATION_TOKENfor Email/SMS OTP, orSTAMP_ATTESTED_SCHEME_P256_OIDCfor OAuth
5
Attach the JSON-encoded stamp to your request as a
X-Stamp-Attested header6
Submit the stamped request to Turnkey’s API
Stampers
Our JS SDK and CLI abstract request stamping for you. If you choose to use an independent client, you will need to implement this yourself. For reference, check out our implementations:API Key Stamper
WebAuthn Stamper
React Native Stamper
iFrame Stamper
Telegram Cloud Storage Stamper
IndexedDb Stamper
CLI
Wallet Stamper
--no-post option to generate stamps without sending anything over the network. This is a useful tool should you have trouble with debugging stamping-related logic. A sample command might look something like: