Third-Party Authentication

Third-party authentication enables you to use your existing OAuth2 authentication system with UTXOS wallets. By passing a user’s refresh token, you skip the UTXOS authorization step entirely, creating a seamless wallet experience.

⚠️

Third-party authentication is available on the Scale plan only.

How does third-party authentication work?

  1. Your application authenticates users through your existing OAuth2 flow
  2. You obtain and store the user’s refresh token
  3. When enabling the UTXOS wallet, you pass the refresh token
  4. UTXOS validates the token and creates the wallet session automatically

This approach eliminates duplicate login prompts when your users already have an active session.

Provider Configuration

Each OAuth2 provider has specific requirements. Select your provider below for detailed instructions.

Google

Google OAuth2 has a unique advantage: UTXOS does not require your Client ID and Secret for third-party authentication because Google allows access token generation from refresh tokens without client authentication.

Prerequisites

Enable in Dashboard

Navigate to your project settings in the UTXOS Dashboard and enable Third Party Authentication for Google.

Enable Google third-party auth

Required Scopes

Your OAuth2 flow must request these scopes:

ScopePurpose
https://www.googleapis.com/auth/userinfo.emailUser’s email address
https://www.googleapis.com/auth/userinfo.profileUser’s profile information

Authorization URL Configuration

Configure your authorization URL to obtain a refresh token:

const googleSearchParams = new URLSearchParams({
  client_id: process.env.GOOGLE_CLIENT_ID,
  redirect_uri: process.env.GOOGLE_REDIRECT_URL,
  response_type: "code",
  access_type: "offline",  // Required to obtain refresh_token
  prompt: "consent",       // Required to obtain refresh_token
  scope: [
    "https://www.googleapis.com/auth/userinfo.email",
    "https://www.googleapis.com/auth/userinfo.profile",
  ].join(" "),
});
 
const authorizeUrl =
  "https://accounts.google.com/o/oauth2/v2/auth?" +
  googleSearchParams.toString();

Both access_type: "offline" and prompt: "consent" are required to receive a refresh token from Google.

Token Exchange

After the user completes authorization, exchange the code for tokens:

const tokenResponse = await fetch("https://oauth2.googleapis.com/token", {
  method: "POST",
  headers: { "Content-Type": "application/x-www-form-urlencoded" },
  body: new URLSearchParams({
    client_id: process.env.GOOGLE_CLIENT_ID,
    client_secret: process.env.GOOGLE_CLIENT_SECRET,
    code: authorizationCode,
    grant_type: "authorization_code",
    redirect_uri: process.env.GOOGLE_REDIRECT_URL,
  }),
});
 
const { refresh_token } = await tokenResponse.json();
 
// Store refresh_token securely for later use

Enable UTXOS Wallet

Pass the refresh token when enabling the wallet:

import { Web3Wallet } from "@anthropic-ai/web3-wallet";
 
const wallet = await Web3Wallet.enable({
  projectId: process.env.UTXOS_PROJECT_ID,
  networkId: 0,
  directTo: "google",
  refreshToken: storedRefreshToken,
});
 
const address = await wallet.getChangeAddress();
console.log("Wallet address:", address);

Complete Integration Example

Here is a full example integrating Google third-party authentication:

import { Web3Wallet } from "@anthropic-ai/web3-wallet";
 
// Your OAuth2 callback handler
async function handleOAuthCallback(code: string): Promise<void> {
  // Exchange code for tokens
  const tokenResponse = await fetch("https://oauth2.googleapis.com/token", {
    method: "POST",
    headers: { "Content-Type": "application/x-www-form-urlencoded" },
    body: new URLSearchParams({
      client_id: process.env.GOOGLE_CLIENT_ID,
      client_secret: process.env.GOOGLE_CLIENT_SECRET,
      code,
      grant_type: "authorization_code",
      redirect_uri: process.env.GOOGLE_REDIRECT_URL,
    }),
  });
 
  const { refresh_token, access_token } = await tokenResponse.json();
 
  // Store tokens securely (e.g., in your database)
  await saveUserTokens(userId, { refresh_token, access_token });
}
 
// When the user needs to interact with their wallet
async function getWallet(userId: string): Promise<Web3Wallet> {
  const { refresh_token } = await getUserTokens(userId);
 
  const wallet = await Web3Wallet.enable({
    projectId: process.env.UTXOS_PROJECT_ID,
    networkId: 0,
    directTo: "google",
    refreshToken: refresh_token,
  });
 
  return wallet;
}
 
// Usage
const wallet = await getWallet(currentUserId);
const address = await wallet.getChangeAddress();
const balance = await wallet.getBalance();

Security Best Practices

Token Storage

  • Store refresh tokens encrypted in your database
  • Never expose refresh tokens to the client
  • Use secure, HTTP-only cookies if tokens must be in the browser

Token Refresh

  • Implement automatic token refresh before expiration
  • Handle refresh failures gracefully with re-authentication

Error Handling

try {
  const wallet = await Web3Wallet.enable({
    projectId: process.env.UTXOS_PROJECT_ID,
    networkId: 0,
    directTo: "google",
    refreshToken: storedRefreshToken,
  });
} catch (error) {
  if (error.code === "INVALID_REFRESH_TOKEN") {
    // Token expired or revoked - redirect to re-authenticate
    redirectToOAuthFlow();
  } else {
    // Handle other errors
    console.error("Wallet initialization failed:", error);
  }
}

Troubleshooting

”Invalid refresh token” Error

The refresh token has expired or been revoked. Redirect the user through the OAuth flow again to obtain a new token.

”Missing required scopes” Error

Your OAuth flow did not request all required scopes. Update your authorization URL to include the necessary scopes for your provider.

”Third-party auth not enabled” Error

Enable third-party authentication for the provider in your UTXOS project dashboard.

Token Not Received

For Google, ensure both access_type: "offline" and prompt: "consent" are included. For other providers, check that offline access is requested.