You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Copy file name to clipboardExpand all lines: mintlify/snippets/sandbox-global-account-magic.mdx
+25-11Lines changed: 25 additions & 11 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -1,6 +1,6 @@
1
-
The Grid sandbox accepts a small set of test helpers for Global Account flows, so you can exercise the full request shape without real OTP delivery, WebAuthn ceremony, or wallet signatures. Email OTP uses a sandbox test inbox. Passkey and wallet signatures use fixed sandbox-only values. OAuth accepts OIDC ID tokens from supported providers; for isolated sandbox tests, you can also pass a JWT-shaped test token. Sandbox skips real IdP signature verification, but still validates token claims, freshness, credential identity, and verify-time nonce binding.
1
+
The Grid sandbox lets you exercise Global Account auth flows without moving real money. Email OTP uses a sandbox test inbox. Passkey auth can use the same browser WebAuthn ceremony as production, and signed wallet actions can use the same decrypted session signing key and `Grid-Wallet-Signature` stamp as production. OAuth accepts OIDC ID tokens from supported providers; for isolated sandbox tests, you can also pass a JWT-shaped test token. Sandbox skips real IdP signature verification, but still validates token claims, freshness, credential identity, and verify-time nonce binding.
2
2
3
-
A wrong magic value or sandbox OIDC authentication failure returns`401 UNAUTHORIZED` with a `reason` field that names the specific check that failed. A malformed OIDC JWT can return `400 INVALID_INPUT` before authentication starts.
3
+
Sandbox-only compatibility values are still available for some flows, but they do not exercise the production-shaped client implementation. Authentication failures return`401 UNAUTHORIZED` with a `reason` field that names the specific check that failed. A malformed OIDC JWT can return `400 INVALID_INPUT` before authentication starts.
4
4
5
5
### Email OTP code
6
6
@@ -24,11 +24,17 @@ curl -X POST "$GRID_BASE_URL/auth/credentials/AuthMethod:abc123/verify" \
24
24
25
25
The sandbox validates the code against the pending OTP state. A wrong, expired, consumed, or locked-out code returns `401 UNAUTHORIZED`.
26
26
27
-
### Passkey assertion signature
27
+
### Passkey WebAuthn ceremony
28
28
29
-
Pass `sandbox-valid-passkey-signature` as `assertion.signature` on `POST /auth/credentials/{id}/verify` when the credential type is `PASSKEY`. The sandbox accepts the rest of the assertion as-is and skips the WebAuthn signature check.
29
+
For new sandbox integrations, use the same WebAuthn calls you plan to use in production.
30
30
31
-
Passkey reauthentication is a two-step `/challenge` → `/verify` flow. The `clientPublicKey` is sent on `/challenge` (so Grid can seal the session signing key to your device) — the magic value bypasses the credential check, not the HPKE plumbing, so the public key is still required.
31
+
1. Generate your own WebAuthn registration challenge and call `navigator.credentials.create()`.
32
+
2. Register the passkey with `POST /auth/credentials`, passing the challenge and attestation returned by the browser.
33
+
3. Reauthenticate with `POST /auth/credentials/{id}/challenge`, passing the P-256 `clientPublicKey` that Grid should seal the session signing key to.
34
+
4. Pass the returned `challenge` into `navigator.credentials.get()` using the returned `credentialId` in `allowCredentials`.
35
+
5. Verify with `POST /auth/credentials/{id}/verify`, passing the browser assertion and echoing `Request-Id` from the challenge response.
36
+
37
+
The sandbox validates the registered credential ID, WebAuthn challenge, origin/RP binding, user-presence bit, assertion signature, and signature counter. A successful verify response includes `encryptedSessionSigningKey`, sealed to the `clientPublicKey`, just like production.
32
38
33
39
```bash
34
40
# 1. /challenge with clientPublicKey
@@ -39,7 +45,7 @@ curl -X POST https://api.lightspark.com/grid/2025-10-13/auth/credentials/AuthMet
39
45
"clientPublicKey": "04f45f2a..."
40
46
}'
41
47
42
-
# 2. /verify with the magic signature, no clientPublicKey
48
+
# 2. /verify with the browser assertion returned by navigator.credentials.get()
43
49
curl -X POST https://api.lightspark.com/grid/2025-10-13/auth/credentials/AuthMethod:abc123/verify \
44
50
-u "$GRID_CLIENT_ID:$GRID_CLIENT_SECRET" \
45
51
-H "Content-Type: application/json" \
@@ -50,12 +56,14 @@ curl -X POST https://api.lightspark.com/grid/2025-10-13/auth/credentials/AuthMet
50
56
"credentialId": "...",
51
57
"clientDataJson": "...",
52
58
"authenticatorData": "...",
53
-
"signature": "sandbox-valid-passkey-signature"
59
+
"signature": "..."
54
60
}
55
61
}'
56
62
```
57
63
58
-
Any other signature returns `401 UNAUTHORIZED` with `reason: "Invalid passkey signature"`.
64
+
<Note>
65
+
The legacy sandbox-only assertion signature `sandbox-valid-passkey-signature` is still accepted for compatibility, but it skips WebAuthn verification and should not be used for production-shaped sandbox tests.
66
+
</Note>
59
67
60
68
### OAuth (OIDC) token
61
69
@@ -115,7 +123,7 @@ curl -X POST https://api.lightspark.com/grid/2025-10-13/auth/credentials/AuthMet
115
123
116
124
### Wallet signature header
117
125
118
-
Pass `sandbox-valid-signature`as the `Grid-Wallet-Signature` HTTP header on any signed-retry flow:
126
+
After verifying an auth credential, decrypt `encryptedSessionSigningKey` with the private key matching the `clientPublicKey` you supplied on verify or refresh. Use the decrypted session signing key to build a Turnkey API-key stamp over the exact `payloadToSign` string returned by Grid, then pass that full stamp as the `Grid-Wallet-Signature` HTTP header on signed flows:
119
127
120
128
-`POST /auth/credentials` (add-additional-credential signed retry)
Any other header value returns `401 UNAUTHORIZED` with `reason: "Invalid Grid-Wallet-Signature"`.
145
+
Sandbox validates that the stamp is a P-256 Turnkey API-key stamp over the exact pending Turnkey payload and that the public key belongs to an active sandbox session for the wallet.
146
+
147
+
<Note>
148
+
The legacy sandbox-only `Grid-Wallet-Signature: sandbox-valid-signature` value is still accepted for compatibility. Use a real session stamp when you want the client implementation to match production.
0 commit comments