Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 5 additions & 5 deletions mintlify/openapi.yaml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion mintlify/snippets/global-accounts/authentication.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -715,7 +715,7 @@ Requires an active session on an *existing* credential on the same account. The
**Response (201):** a plain `AuthMethod`.
</Step>
<Step title="Activate the new credential">
Activate the new credential the same way you would activate the first credential of that type — `EMAIL_OTP` and `OAUTH` go straight to `POST /auth/credentials/{id}/verify` with a fresh `clientPublicKey`; `PASSKEY` first calls `POST /auth/credentials/{id}/challenge` with the `clientPublicKey` to get a Grid-issued WebAuthn challenge, then `POST /auth/credentials/{id}/verify` with the assertion and the `Request-Id` header.
Activate the new credential the same way you would activate the first credential of that type — `OAUTH` goes straight to `POST /auth/credentials/{id}/verify` with a fresh `clientPublicKey`; `EMAIL_OTP` uses the `otpEncryptionTargetBundle` from the signed-retry registration response when present, or first calls `POST /auth/credentials/{id}/challenge` if the bundle is absent; `PASSKEY` first calls `POST /auth/credentials/{id}/challenge` with the `clientPublicKey` to get a Grid-issued WebAuthn challenge, then `POST /auth/credentials/{id}/verify` with the assertion and the `Request-Id` header.
</Step>
</Steps>

Expand Down
4 changes: 2 additions & 2 deletions mintlify/snippets/global-accounts/client-keys.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -118,7 +118,7 @@ func generateClientKeyPair() -> ClientKeyPair {

`EMAIL_OTP` credentials never send the OTP code in plaintext. Instead, the client HPKE-encrypts the code (together with its `publicKeyHex`) to an enclave key, so the code is unreadable in transit and Grid is only a pass-through.

Grid returns an `otpEncryptionTargetBundle` from `POST /auth/credentials` (registration) or `POST /auth/credentials/{id}/challenge` (re-issue). It's a signed enclave bundle whose `data` field is hex-encoded JSON carrying the enclave's HPKE target key as `targetPublic`. Pull out `targetPublic`, HPKE-encrypt `{ otp_code, public_key }` to it, and submit the library's `{ encappedPublic, ciphertext }` output as `encryptedOtpBundle` on `POST /auth/credentials/{id}/verify`.
Grid returns an `otpEncryptionTargetBundle` whenever it initiates or reissues an OTP challenge, including `POST /auth/credentials/{id}/challenge` and add-EMAIL_OTP signed-retry responses. First-time EMAIL_OTP wallet bootstrap registration can omit it; if the registration response has no bundle, call `POST /auth/credentials/{id}/challenge` for that credential before verifying. The bundle is a signed enclave bundle whose `data` field is hex-encoded JSON carrying the enclave's HPKE target key as `targetPublic`. Pull out `targetPublic`, HPKE-encrypt `{ otp_code, public_key }` to it, and submit the library's `{ encappedPublic, ciphertext }` output as `encryptedOtpBundle` on `POST /auth/credentials/{id}/verify`.

Use an HPKE library so you don't hand-roll the suite, `info`, or AAD — `@turnkey/crypto`'s `hpkeEncrypt` + `formatHpkeBuf` produce exactly the shape the enclave expects:

Expand All @@ -127,7 +127,7 @@ Use an HPKE library so you don't hand-roll the suite, `info`, or AAD — `@turnk
import { hpkeEncrypt, formatHpkeBuf } from "@turnkey/crypto";
import { hexToBytes } from "@noble/hashes/utils";

// otpEncryptionTargetBundle: from POST /auth/credentials or /challenge
// otpEncryptionTargetBundle: from the registration response when present, or /challenge
// clientPublicKeyHex: the uncompressed public key you generated in step 1
// otp: the code the user typed ("000000" in sandbox)
function buildEncryptedOtpBundle(
Expand Down
Loading
Loading