Not Organic / Integration guides
Authentication
Choose the correct trust boundary, request the minimum scope, and bind credentials to the key that will use them.
Trusted server exchange
POST /v1/auth/token/exchange accepts JSON with assertion, dpop_jwk, and optional space-separated scope. The assertion represents a product-authorized account and capability set. Issuer, audience, product, account identity, and signing key must match the configured integration.
Assertions expire within 60 seconds and are single-use. Requested scopes cannot exceed the assertion’s capabilities. The returned token is DPoP-bound and expires in 300 seconds.
{
"assertion": "<fresh signed product assertion>",
"dpop_jwk": { "kty": "EC", "crv": "P-256", "x": "<x>", "y": "<y>" },
"scope": "wallet:read usage:read"
}The angle-bracket values are descriptive placeholders. Only the public proof key is submitted. If an assertion already binds a key thumbprint, the exchange must use that same key.
Browser authorization with PKCE
- Generate a cryptographically random PKCE verifier, its SHA-256 base64url challenge, and an unpredictable state value. Keep the verifier and state available only for this authorization attempt.
- Navigate to the portal’s
/authorizeendpoint with the parameters below. The user signs in and approves the requested scopes. - On your callback, verify state exactly, reject unexpected callbacks, and use the returned single-use code.
- POST the code, verifier, client ID, exact redirect URI, and public proof key to the gateway’s
/v1/public/token. - Use the access token with a fresh DPoP proof on protected requests. Keep the proof private key under the client’s control.
| Authorization parameter | Value |
|---|---|
response_type | code |
client_id | Your HTTPS origin, for example https://client.example. |
redirect_uri | An absolute callback on that same origin, without a fragment. |
code_challenge_method | S256 |
code_challenge | Base64url SHA-256 of the verifier, without padding. |
scope | A space-separated subset of permitted public-client capabilities. |
state | An unpredictable value checked by your callback. Always supply it. |
{
"code": "<code from the verified callback>",
"code_verifier": "<original 43–128 character verifier>",
"client_id": "https://client.example",
"redirect_uri": "https://client.example/callback",
"dpop_jwk": { "kty": "EC", "crv": "P-256", "x": "<x>", "y": "<y>" }
}Loopback HTTP origins are allowed by the validator for local development. That does not automatically enable gateway CORS for an origin. Configure CORS independently. Arbitrary native callback schemes are not accepted; the implementation has an explicit Keating mobile registration.
Proof on every protected request
Authorization: DPoP <access_token>
DPoP: <fresh signed proof>The proof uses typ: dpop+jwt and a public JWK in its header. It binds htm to the HTTP method, htu to the target URL, and ath to a SHA-256 hash of the access token. Supply fresh issue/expiry times and a unique jti. The gateway rejects replayed proofs.
Use createDpopProofFactory(keyPair) from the SDK to construct proofs. Passing { keyPair } is not the function’s signature. The SDK helper generates an extractable key pair; browser integrations requiring non-extractable keys must supply a suitable Web Crypto key and public JWK themselves.
Scopes and device sessions
Typical browser scopes include wallet:read, usage:read, billing:checkout, inference scopes, and realtime:connect. The public-client validator does not grant arbitrary account-evolution, sandbox, or response-deletion access.
For an explicitly requested persistent device session, include device_session: true and optionally device_name (1–120 characters) in the public exchange. Store the returned refresh credential in secure device storage. The current session lifetime is 30 days.
POST /v1/public/device/token accepts grant_type: "refresh_token" and refresh_token, with optional narrower scope. Refresh is proof-bound and rotates the refresh credential; replace the old credential atomically. Use POST /v1/public/device/revoke to revoke it. Follow the device-specific proof contract in apps/gateway/src/auth.ts; ordinary access-token proofs are not interchangeable with refresh proofs.