| 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 account action for the lifetime of the session (default 15 minutes). |
1. Generate a client key pair
Generate a fresh P-256 key pair for every authentication and for every wallet export. The public key is sent to Grid asclientPublicKey — for PASSKEY credentials this happens on POST /auth/credentials/{id}/challenge; for EMAIL_OTP and OAUTH it happens on POST /auth/credentials/{id}/verify; for wallet export it goes on both /export calls. 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 — through your integrator backend. 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 Sign a payloadToSign). The decrypt path below applies only to production.3. Decrypt the session signing key
4. Sign a payloadToSign
Grid returns payloadToSign strings from several endpoints:
POST /quotes(when the source is a Global Account) — 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.
Grid-Wallet-Signature header on the retry (and, for endpoints that use it, the Request-Id header echoed back from the 202).
In sandbox, send
Grid-Wallet-Signature: sandbox-valid-signature for any signed account action. Sandbox skips the ECDSA check, so you don’t need a real session signing key or an extracted payloadToSign. The signing pattern below applies only to production.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.