| Key pair | Where it lives | What it does |
|---|---|---|
| Client key pair (P-256) | On the customer’s device, generated fresh per verification request | Used as the HPKE recipient key so Grid can encrypt the session signing key to the client. Ephemeral — one pair per POST /auth/credentials/{id}/verify call. |
| Session signing key (P-256) | Issued by Grid, encrypted to the client public key, decrypted and held on the device | Signs every wallet action for the lifetime of the session (default 15 minutes). |
1. Generate a client key pair
Generate a fresh P-256 key pair for everyPOST /auth/credentials/{id}/verify call and for every wallet export. Keep the private key in device-local secure storage (browser IndexedDB gated by Web Crypto’s non-extractable flag, iOS Keychain, Android Keystore). Send the public key hex-encoded — a 130-character string starting with 04 — to your integrator backend, which passes it to Grid as clientPublicKey. The Web Crypto, iOS, and Android APIs shown below all produce this format natively.
The private key must not leave the device. Your integrator backend only ever sees
publicKeyHex.2. Verify the credential and receive the encrypted session signing key
Your client sendspublicKeyHex to your integrator backend along with whatever the credential type requires (OTP value, OIDC token, or WebAuthn assertion — see Authentication). Your backend calls POST /auth/credentials/{id}/verify and returns the encryptedSessionSigningKey from Grid’s response to the client.
Grid encrypts the session signing key with HPKE (RFC 9180) using the suite:
- KEM: DHKEM(P-256, HKDF-SHA256)
- KDF: HKDF-SHA256
- AEAD: AES-256-GCM
In sandbox,
encryptedSessionSigningKey is a stub — random bytes shaped like a real HPKE payload but not encrypted to your clientPublicKey. Decrypt attempts will fail. Skip this step entirely on sandbox and use the literal Grid-Wallet-Signature: sandbox-valid-signature for any signed action (see Authorize a payloadToSign). The decrypt path below applies only to production.3. Decrypt the session signing key
4. Authorize a payloadToSign
Grid returns payloadToSign strings from several endpoints:
POST /quotes(when the source is an Embedded Wallet) — the quote’spaymentInstructions[].accountOrWalletInfo.payloadToSign.POST /auth/credentials(adding an additional credential) — 202 response body.DELETE /auth/credentials/{id},DELETE /auth/sessions/{id},POST /internal-accounts/{id}/export— all 202 response bodies.
| Flow | What to send in Grid-Wallet-Signature |
|---|---|
Quote execution (POST /quotes/{quoteId}/execute) | A base64 ECDSA signature over the quote payloadToSign. |
Signed retries (POST /auth/credentials, DELETE /auth/credentials/{id}, DELETE /auth/sessions/{id}, POST /internal-accounts/{id}/export) | A full API-key stamp over the payloadToSign, built with the session API keypair. Also echo Request-Id from the 202 response. |
In sandbox, send
Grid-Wallet-Signature: sandbox-valid-signature for any signed account action. Sandbox skips signature and stamp verification, so you don’t need a real session signing key or an extracted payloadToSign. The authorization patterns below apply only to production.Quote execution signature
For quote execution, sign the quotepayloadToSign with the session signing key. The signature is ECDSA over SHA-256, DER-encoded, then base64-encoded.
Signed-retry stamp
For signed retries, use the session API keypair to build a full API-key stamp over thepayloadToSign. Send that complete stamp as Grid-Wallet-Signature and include the Request-Id returned with the challenge.
Session lifetime
Sessions are valid for 15 minutes by default. TheAuthSession.expiresAt field tells you exactly when the session signing key stops being accepted. After expiry, the client must re-verify the credential (see Authentication) to obtain a fresh session.