Skip to main content

Privy Integration

Privy provides embedded wallets, social login, and user management for web3 apps. You can use Privy as your auth provider for Privacy Boost, letting users log in with email, social accounts, or wallets through Privy while using Privacy Boost for private transactions.

How It Works

Privy authenticates your users and issues JWTs. Your backend forwards the Privacy Boost login payload with the Privy token attached. Privacy Boost validates the token against Privy’s JWKS endpoint. Privy Authentication Flow

Server-Side Setup

Your app must be configured with the privy_jwt auth method. Contact the Privacy Boost team with:
  • Privy App ID — Your Privy application ID (found in the Privy Dashboard)
  • JWKS URL — Privy’s JWKS endpoint: https://auth.privy.io/api/v1/apps/<YOUR_PRIVY_APP_ID>/.well-known/jwks.json
The backend configuration looks like:
{
  "privy_app_id": "clx...",
  "jwks_url": "https://auth.privy.io/api/v1/apps/clx.../.well-known/jwks.json"
}

Client-Side Integration

1. Set Up Privy

Follow Privy’s React quickstart to set up PrivyProvider:
import { PrivyProvider } from '@privy-io/react-auth';

function App() {
  return (
    <PrivyProvider appId="clx..." config={{ /* ... */ }}>
      <YourApp />
    </PrivyProvider>
  );
}

2. Create a Token Provider

The token provider gets the Privy auth token and forwards it with the Privacy Boost login payload:
import { usePrivy } from '@privy-io/react-auth';

function usePrivacyBoostAuth() {
  const { getAccessToken } = usePrivy();

  const tokenProvider = async (loginPayload: any) => {
    const privyToken = await getAccessToken();

    const res = await fetch('https://your-backend.com/api/privacy-boost/auth', {
      method: 'POST',
      headers: {
        'Content-Type': 'application/json',
        'Authorization': `Bearer ${privyToken}`,
      },
      body: JSON.stringify(loginPayload),
    });

    return await res.json(); // { token, expiresIn }
  };

  return { tokenProvider };
}

3. Authenticate with Privacy Boost

const { tokenProvider } = usePrivacyBoostAuth();

await sdk.auth.authenticate(adapter, {
  type: 'walletDerived',
  tokenProvider,
});

4. Implement the Backend Endpoint

Your backend receives the SDK’s login payload, verifies the Privy token, and forwards to Privacy Boost:
app.post('/api/privacy-boost/auth', async (req, res) => {
  // 1. Extract Privy token from Authorization header
  const privyToken = req.headers.authorization?.replace('Bearer ', '');
  if (!privyToken) return res.status(401).json({ error: 'Missing Privy token' });

  // 2. Forward to Privacy Boost with the Privy token attached
  const pbResponse = await fetch('https://test-api.privacy-boost.sunnyside.io/indexer/auth/token', {
    method: 'POST',
    headers: { 'Content-Type': 'application/json' },
    body: JSON.stringify({
      ...req.body,             // SDK's login payload
      privy_token: privyToken, // Privy JWT — Privacy Boost validates this via JWKS
    }),
  });

  const data = await pbResponse.json();
  res.json({
    token: data.access_token,
    expiresIn: data.expires_in,
  });
});
You don’t need to validate the Privy JWT yourself. Privacy Boost fetches Privy’s JWKS and verifies the token signature, audience, and expiry.

Using Privy’s Embedded Wallet

If your users use Privy’s embedded wallet (no MetaMask), you can create a wallet adapter from Privy’s wallet provider:
import { useWallets } from '@privy-io/react-auth';

function usePrivyWalletAdapter() {
  const { wallets } = useWallets();
  const embeddedWallet = wallets.find((w) => w.walletClientType === 'privy');

  const getAdapter = async () => {
    if (!embeddedWallet) throw new Error('No embedded wallet');
    const provider = await embeddedWallet.getEthereumProvider();

    return {
      async connect() {
        const accounts = await provider.request({ method: 'eth_requestAccounts' });
        const chainId = await provider.request({ method: 'eth_chainId' });
        return { address: accounts[0], chainId: parseInt(chainId, 16) };
      },
      async disconnect() {},
      async signMessage(message: string) {
        const accounts = await provider.request({ method: 'eth_accounts' });
        return provider.request({ method: 'personal_sign', params: [message, accounts[0]] });
      },
      async signTypedData(typedData: string) {
        const accounts = await provider.request({ method: 'eth_accounts' });
        return provider.request({ method: 'eth_signTypedData_v4', params: [accounts[0], typedData] });
      },
      async sendTransaction(tx: unknown) {
        return provider.request({ method: 'eth_sendTransaction', params: [tx] });
      },
      async getAddress() {
        const accounts = await provider.request({ method: 'eth_accounts' });
        return accounts[0];
      },
      async getChainId() {
        const chainId = await provider.request({ method: 'eth_chainId' });
        return parseInt(chainId, 16);
      },
    };
  };

  return { getAdapter, hasWallet: !!embeddedWallet };
}

Next Steps

Continue with setup: Or explore other auth methods:
  • Custom JWT — For Auth0, Firebase, Supabase, Clerk, or OIDC providers
  • Dynamic — For Dynamic wallet connection and embedded wallets