Skip to main content
Start with the Setup Guide if you still need to wire createAggClient, AggProvider, or AggAuthProvider. After sign-in, see Token Refresh for session renewal, Account Linking for adding additional providers, and Partner External ID Linking if you need to attach your own internal user ID to the AGG profile.
AGG supports six authentication providers:
  • siwe for Ethereum wallets
  • siws for Solana wallets
  • google for Google OAuth
  • twitter for X OAuth
  • apple for Apple Sign In
  • email for magic-link email sign-in

How It Works

All flows start with client.authStart(...), but they complete in two different ways:

Bot Protection (challenge_required)

For wallet (siwe, siws) and email (email) providers, AGG enforces an optional Cloudflare Turnstile challenge when your app crosses its configured user-count threshold. OAuth providers (google, twitter, apple) bypass this layer — the identity provider is already the human proof. When the challenge is active, POST /auth/start may return an extra response type:
Your flow becomes:
  1. Call client.authStart({ provider: "siwe" }).
  2. If the response type is challenge_required, render the Cloudflare Turnstile widget using the returned siteKey.
  3. On solve, resubmit client.authStart({ provider: "siwe", turnstileToken: "<cf-token>" }).
  4. The server verifies the token against its linked widget and returns the normal nonce / magic_link response.
  5. An invalid or reused token returns 403 — retry with a fresh Turnstile solve.

SDK: SIWE

SIWE is fully client-side and does not redirect.
If your browser app wants the refresh token set as an HttpOnly cookie instead, configure the SDK client with authDelivery: "cookie-refresh". In that mode, verify() and exchangeAuthCode() may omit refreshToken from the JSON response. That cookie stays on the AGG API host and is scoped to /auth routes.

SDK: SIWS

SIWS is also fully client-side and does not redirect.

SIWS with Ledger

Ledger is not a separate AGG auth flow. It uses the exact same SIWS contract:
  1. client.authStart({ provider: "siws" })
  2. client.buildSiwsMessage(...)
  3. wallet.signMessage(new TextEncoder().encode(message))
  4. bs58.encode(signature)
  5. client.verify({ message, signature })
This matters because Ledger supports signMessage() but not Phantom’s wallet-specific signIn() helper. AGG’s SIWS recipe stays Ledger-compatible by building the message in the dapp and signing the raw UTF-8 bytes directly.

SDK: Google / Twitter / Apple / Email

These four providers all use the same redirect-based flow.
After the user authenticates, AGG redirects back with a one-time auth code:
Exchange that code for tokens on the redirect target page:
The auth code is single-use and expires quickly, so exchange it immediately. Use @agg-build/auth when you want AGG’s connect/sign-in UI without forcing wallet dependencies into @agg-build/ui. See the Connect Button reference for the component surface shown below.

Mixed providers

Browse the live Connect Button reference.

Dedicated callback pages

If your app uses a standalone callback route, use useAggAuthCallback():

React: useAggAuth

useAggAuth keeps the documented wallet ergonomics for custom UIs.

Ethereum

Solana

Token storage

Tokens are never written to storage. They live in process memory only. What the SDK persists to localStorage (keyed by appId) is a non-sensitive hint — the user’s id, username, avatar and wallet address, plus a wasAuthenticated flag — used to bootstrap your UI without a flash of signed-out state. Restoring that hint sets authStatus to "unknown", not "authenticated". What survives a reload therefore depends on authDelivery:
Set persistSession: false to opt out of the hint entirely.

React Native

localStorage does not exist in React Native, so nothing is persisted and isAuthenticated flips to false on every app restart. cookie-refresh is not the answer either — HttpOnly cookies don’t survive there. Keep the default "body" mode, persist the refresh token yourself, and seed it back on boot with setSession():
Store the refresh token in the platform keystore (Keychain / Keystore via expo-secure-store or react-native-keychain) — not AsyncStorage, which is unencrypted.

Installation matrix

Setup Guide

Wire the base client, providers, and WebSocket connection first.

Token Refresh

Renew access tokens and recover gracefully from session expiry.

Account Linking

Connect additional OAuth providers to the current user profile.

User Notifications

Reuse the same session for authenticated WebSocket events.

Bot Protection

Render and verify Cloudflare Turnstile challenges during sign-in.