Skip to main content

Dynamic Integration

Dynamic provides wallet connection, embedded wallets, and multi-chain auth for web3 apps. You can use Dynamic as your auth provider for Privacy Boost, letting users log in through Dynamic’s UI while using Privacy Boost for private transactions.

How It Works

Dynamic authenticates your users and issues JWTs. Your backend forwards the Privacy Boost login payload with the Dynamic JWT attached. Privacy Boost validates the token against Dynamic’s JWKS endpoint using the custom_jwt auth method. Dynamic Authentication Flow

Server-Side Setup

Your app must be configured with the custom_jwt auth method. Contact the Privacy Boost team with:
  • JWKS URL — Dynamic’s JWKS endpoint for your environment: https://app.dynamic.xyz/api/v0/sdk/<YOUR_ENVIRONMENT_ID>/.well-known/jwks
  • Issuer (optional) — https://app.dynamic.xyz/<YOUR_ENVIRONMENT_ID>
  • Audience (optional) — Your Dynamic environment ID
The backend configuration looks like:
{
  "jwks_url": "https://app.dynamic.xyz/api/v0/sdk/<ENVIRONMENT_ID>/.well-known/jwks",
  "issuer": "https://app.dynamic.xyz/<ENVIRONMENT_ID>",
  "audience": "<ENVIRONMENT_ID>"
}
Find your Environment ID in the Dynamic Dashboard under Developer > SDK & API Keys.

Client-Side Integration

1. Set Up Dynamic

Follow Dynamic’s React quickstart to set up DynamicContextProvider:
import { DynamicContextProvider } from '@dynamic-labs/sdk-react-core';
import { EthereumWalletConnectors } from '@dynamic-labs/ethereum';

function App() {
  return (
    <DynamicContextProvider
      settings={{
        environmentId: 'your-environment-id',
        walletConnectors: [EthereumWalletConnectors],
      }}
    >
      <YourApp />
    </DynamicContextProvider>
  );
}

2. Create a Token Provider

The token provider gets the Dynamic auth token and forwards it with the Privacy Boost login payload:
import { useDynamicContext } from '@dynamic-labs/sdk-react-core';

function usePrivacyBoostAuth() {
  const { authToken } = useDynamicContext();

  const tokenProvider = async (loginPayload: any) => {
    if (!authToken) throw new Error('Not logged in to Dynamic');

    const res = await fetch('https://your-backend.com/api/privacy-boost/auth', {
      method: 'POST',
      headers: {
        'Content-Type': 'application/json',
        'Authorization': `Bearer ${authToken}`,
      },
      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, and forwards to Privacy Boost with the Dynamic JWT:
app.post('/api/privacy-boost/auth', async (req, res) => {
  // 1. Extract Dynamic token from Authorization header
  const dynamicToken = req.headers.authorization?.replace('Bearer ', '');
  if (!dynamicToken) return res.status(401).json({ error: 'Missing Dynamic token' });

  // 2. Forward to Privacy Boost with the Dynamic JWT 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
      custom_jwt_token: dynamicToken, // Dynamic JWT — validated via JWKS
    }),
  });

  const data = await pbResponse.json();
  res.json({
    token: data.access_token,
    expiresIn: data.expires_in,
  });
});

Using Dynamic’s Wallet Connector

If your users connect wallets through Dynamic, you can use the connected wallet’s provider with the Privacy Boost SDK:
import { useDynamicContext } from '@dynamic-labs/sdk-react-core';

function usePrivacyBoostWithDynamic() {
  const { primaryWallet } = useDynamicContext();

  const getAdapter = async () => {
    if (!primaryWallet) throw new Error('No wallet connected');
    const provider = await primaryWallet.getWalletClient();

    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 };
}

Next Steps

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