Agnic
Authentication

OAuth2 Integration

Let users authorize your app to sign X402 transactions on their behalf

OAuth2 Integration

OAuth2 lets your application request permission from Agnic users to sign X402 transactions on their behalf. Users set their own spending limits and can revoke access anytime.

Why OAuth2?

  • User-controlled limits — Users set daily/monthly spending caps at consent
  • Revocable access — Users can disconnect your app anytime
  • Network selection — Users choose which networks to allow
  • Long-lived tokens — Access tokens last 30–60 days with refresh

Register Your Application

Before your first OAuth2 call, register your app and get it approved.

1. Create a client in the dashboard

Go to app.agnic.ai/oauth-clients and click New Client. Registration is a three-step form.

Step 1 — KYC information

Required to operate an OAuth client on Agnic. These fields lock after approval.

FieldRequiredNotes
Full nameYesLegal name of the responsible party
Phone numberYes
CountryYes
AddressYes

Step 2 — App information

Shown to your users on the consent screen; editable any time.

FieldRequiredNotes
App nameYesDisplayed to users when they authorize
User support emailYesWhere users reach you about your app
Contact emailsNoWhere Agnic reaches you about your client (add as many as you like)

Step 3 — OAuth configuration

FieldRequiredNotes
Authorized JavaScript originsNoCORS-origin allowlist for browser flows (e.g. https://yourapp.com)
Authorized redirect URIsYes, ≥1Exact-match callback URLs. Add one per environment
Accept termsYes

2. Save your credentials

On creation you receive:

  • Client ID — always visible on the client's detail page (copyable)
  • Client Secretshown once in a modal. Copy it immediately; it is never displayed again. You can regenerate from the detail page, which invalidates the previous secret.

Store the secret in a server-side vault. Public clients (SPAs, mobile, CLIs) should use PKCE instead of embedding a secret.

3. Wait for approval

New clients start in Pending Approval status. You can see this as a badge on the client detail page.

While pending, the /oauth/authorize endpoint will reject your client_id. Your client becomes usable only after Agnic approves it. You'll be notified at the contact emails you provided.

Status badges you may see on the detail page:

StatusMeaning
Pending ApprovalAwaiting Agnic review — cannot run OAuth flows
ApprovedReady for production
RejectedReview rejected — reason shown on the page
RevokedAccess permanently disabled

Authorization Flow

Step 1: Redirect to Authorization

Redirect users to our authorization endpoint. Include PKCE for any non-confidential client.

https://api.agnic.ai/oauth/authorize?
  client_id=<your client id>
  &redirect_uri=https://yourapp.com/callback
  &response_type=code
  &scope=payments:sign+balance:read
  &state=<random csrf token>
  &code_challenge=<base64url(sha256(verifier))>
  &code_challenge_method=S256

Step 2: User Grants Permission

The user logs in, sets spending limits (per-transaction, daily, monthly), selects allowed networks, and approves your app.

Step 3: Receive Authorization Code

User is redirected back to your app with an authorization code:

https://yourapp.com/callback?code=abc123&state=<original state>

On failure, the callback carries error and (usually) error_description instead:

https://yourapp.com/callback?error=access_denied&error_description=User%20declined

Always verify state matches the value you sent before doing anything else.

Step 4: Exchange for Tokens

Exchange the code for access and refresh tokens. redirect_uri must match the one you sent in Step 1 exactly.

curl -X POST https://api.agnic.ai/oauth/token \
  -H "Content-Type: application/json" \
  -d '{
    "grant_type": "authorization_code",
    "code": "abc123",
    "redirect_uri": "https://yourapp.com/callback",
    "client_id": "<your client id>",
    "code_verifier": "<the PKCE verifier>"
  }'

Confidential clients (server-side apps with a stored secret) include client_secret instead of, or in addition to, code_verifier.

Token Response

{
  "access_token": "agnic_at_abc123...",
  "refresh_token": "agnic_rt_xyz789...",
  "token_type": "Bearer",
  "expires_in": 2592000,
  "scope": "payments:sign balance:read"
}

Token Expiration:

  • Access tokens: 30–60 days (varies by client type)
  • Refresh tokens: 90 days
  • N8N tokens: 1 year (for automation workflows)

Persist expires_at = now + expires_in * 1000 and refresh before expiry (a 5-minute buffer is a good default) so an in-flight request never hits a 401.

Using the Access Token

# Check user's balance
curl https://api.agnic.ai/api/balance \
  -H "Authorization: Bearer agnic_at_abc123..."

# Make an AI Gateway request
curl https://api.agnic.ai/v1/chat/completions \
  -H "Authorization: Bearer agnic_at_abc123..." \
  -H "Content-Type: application/json" \
  -d '{
    "model": "openai/gpt-4o",
    "messages": [{"role": "user", "content": "Hello!"}]
  }'

# Get transaction history
curl https://api.agnic.ai/api/transactions \
  -H "Authorization: Bearer agnic_at_abc123..."

Refreshing Tokens

When the access token is about to expire, exchange the refresh token for a new pair:

curl -X POST https://api.agnic.ai/oauth/token \
  -H "Content-Type: application/json" \
  -d '{
    "grant_type": "refresh_token",
    "refresh_token": "agnic_rt_xyz789...",
    "client_id": "<your client id>"
  }'

If refresh fails (expired, revoked, or user disconnected your app), destroy the local session and restart the authorization flow.

Authorization Parameters

ParameterRequiredDescription
client_idYesThe Client ID issued in /oauth-clients
redirect_uriYesMust exact-match one of your registered Authorized Redirect URIs
response_typeYesMust be code
scopeNoSpace-separated scopes (default: payments:sign balance:read)
stateYesCSRF token — returned unchanged on the callback
code_challengeRecommendedBase64url(SHA256(code_verifier)) — required for public clients
code_challenge_methodWith code_challengeMust be S256
promptNoControls consent behavior — see below
displayNopopup for popup-style auth windows
login_hintNoPre-fill the email on the login screen

Scopes

See the full list at Available Scopes. Common combinations:

  • payments:sign balance:read — most apps (charge the user, read balance)
  • payments:sign balance:read transactions:read — apps that show spend history

Prompt Parameter

The prompt parameter follows the OpenID Connect standard:

ValueBehavior
(omitted)Auto-approve if user previously consented
noneSilent auth only — error if consent needed
consentForce consent screen even if previously consented
loginForce re-authentication before authorization

Returning users are auto-approved by default (like Google/GitHub). Use prompt=consent to force users to review permissions again.

PKCE (Required for Public Clients)

Public clients — single-page apps, mobile, CLIs — cannot safely store a client_secret. PKCE replaces it with a per-flow secret.

// 1. Generate a verifier (random 32+ bytes, base64url)
const codeVerifier = base64UrlEncode(crypto.getRandomValues(new Uint8Array(32)));

// 2. Derive the challenge
const codeChallenge = base64UrlEncode(
  await crypto.subtle.digest('SHA-256', new TextEncoder().encode(codeVerifier))
);

// 3. Send the challenge on /oauth/authorize
const authUrl = new URL('https://api.agnic.ai/oauth/authorize');
authUrl.search = new URLSearchParams({
  client_id: '<your client id>',
  redirect_uri: 'https://yourapp.com/callback',
  response_type: 'code',
  scope: 'payments:sign balance:read',
  state: crypto.randomUUID(),
  code_challenge: codeChallenge,
  code_challenge_method: 'S256',
}).toString();

// 4. After the callback, send the verifier on /oauth/token
const tokenResponse = await fetch('https://api.agnic.ai/oauth/token', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    grant_type: 'authorization_code',
    code: authCode,
    redirect_uri: 'https://yourapp.com/callback',
    client_id: '<your client id>',
    code_verifier: codeVerifier,
  }),
});

Store the code_verifier in a short-lived session cookie or server-side session between Step 1 and Step 4, and clear it after use.

CLI Client

The agnic CLI (v2.0.0+) uses OAuth2 Authorization Code + PKCE to authenticate via the browser — the same pattern as gh auth login, vercel login, and stripe login.

Client ID: agnic_cli

Flow:

  1. CLI starts a localhost HTTP server on a random port
  2. Browser opens to api.agnic.ai/oauth/authorize with PKCE challenge
  3. User signs in and sets spending limits on the consent screen
  4. Browser redirects to http://localhost:<port>/callback with auth code
  5. CLI exchanges code + PKCE verifier for tokens (90-day expiry)

Security:

  • PKCE is required for CLI clients (server rejects without code_challenge)
  • Localhost redirect only (http://localhost:<port>/callback or http://127.0.0.1:<port>/callback)
  • HTTP is correct for loopback per RFC 8252 §7.3
  • Server binds to 127.0.0.1 only (no network exposure)
  • Random ephemeral port, state parameter verified, 5-minute timeout
agnic auth login
# Opens browser → sign in → set limits → authenticated!

Reference Implementation

A full working OAuth2 integration (Next.js, PKCE, refresh, popup flow, session storage) lives in the PixelAI reference app. Use it as a template when wiring up your own client.

Next Steps