Exchange Auth Intent

Exchange a settled auth intent for a JWT
View as Markdown

Exchange for JWT

After the agent pays the auth challenge, exchange the intent for a JWT:

1import { Gwop } from "@gwop/sdk";
2
3const gwop = new Gwop({
4 merchantApiKey: process.env.GWOP_MERCHANT_API_KEY,
5});
6
7const { result: token } = await gwop.authIntents.exchange({
8 authIntentId: "ai_mn5e49p01TJe5YUJ-Cw",
9 idempotencyKey: crypto.randomUUID(),
10});
11
12console.log(token.accessToken); // RS256-signed JWT
13console.log(token.principal.sub); // "base:0x742d..." or "solana:7sSi..."
14console.log(token.account.isNewAccount); // true on first auth

Parameters

FieldTypeRequiredDescription
authIntentIdstringYesThe authIntentId from authIntents.create()
idempotencyKeystringNoUUID v4 for safe retries

Response

The response contains:

FieldDescription
accessTokenRS256-signed JWT for authenticating subsequent requests
principal.subWallet identity: {chain}:{address}
account.isNewAccounttrue if this is the wallet’s first authentication

JWT sub format

The sub claim identifies the wallet:

base:0x742d35Cc6634C0532925a3b844Bc9e7595f5bA16
solana:7sSi2XK9pJuqMV9p4Lz3kxBRtxYRPcC5Yp7CYGkaFqJ

Parse it to extract the chain and address:

1const [chain, address] = token.principal.sub.split(":");
2// chain = "base", address = "0x742d..."

Errors

Intent not settled (402)

The agent hasn’t paid the challenge yet:

1import * as errors from "@gwop/sdk/models/errors";
2
3try {
4 await gwop.authIntents.exchange({ authIntentId, idempotencyKey: crypto.randomUUID() });
5} catch (err) {
6 if (err instanceof errors.ErrorResponse && err.statusCode === 402) {
7 // err.data$.error.code = "AUTH_INTENT_NOT_SETTLED"
8 // err.data$.error.message = "Auth intent not yet settled. The agent has not paid."
9 // Poll and retry — the agent may still be paying
10 }
11}

HTTP 402 (Payment Required) is the correct status here — the agent hasn’t paid the auth challenge. Your backend should poll and retry with backoff until the agent completes payment or the intent expires.

Intent not found (404)

1// err.data$.error.code = "AUTH_INTENT_NOT_FOUND"
2// err.data$.error.message = "Auth intent not found"

Next step