Clerk-Crossmint-Supabase Integration Flow
Overview
BlockDrive uses a three-service integration pattern: Clerk for identity, Crossmint for embedded wallets, and Supabase for data persistence. This creates a seamless experience where users authenticate once and automatically receive multichain blockchain wallets (Solana + EVM chains) linked to their account.
When to Use
Activate this skill when:
- •Understanding the complete BlockDrive auth architecture
- •Implementing wallet-to-user linking
- •Syncing multichain wallet addresses to the database
- •Troubleshooting the auth/wallet flow
- •Extending the integration pattern for new chains
Complete Architecture
code
┌─────────────────────────────────────────────────────────────────┐ │ BLOCKDRIVE AUTH ARCHITECTURE │ ├─────────────────────────────────────────────────────────────────┤ │ │ │ ┌──────────┐ ┌──────────────┐ ┌──────────┐ │ │ │ CLERK │────▶│ CROSSMINT │────▶│ SUPABASE │ │ │ │ Identity │ │ Multi-Wallet │ │ Database │ │ │ └──────────┘ └──────────────┘ └──────────┘ │ │ │ │ │ │ │ │ │ │ │ │ 1. User signs in 2. Creates wallets 3. Multi-chain │ │ via Clerk on ALL chains addresses stored │ │ │ │ ──────────────────────────────────────────────────────────── │ │ │ │ User Experience: Sign in once → Wallets automatically created │ │ No seed phrases, no wallet extensions, gas-sponsored txns │ │ Supported Chains: Solana + Ethereum + Base + Polygon + more │ │ │ └─────────────────────────────────────────────────────────────────┘
Key Benefits
- •✅ Multichain from Day 1: Single auth creates wallets on Solana + 50+ EVM chains
- •✅ Automatic: Users get wallets without manual setup
- •✅ Gas Sponsored: Crossmint pays for transaction fees
- •✅ Non-Custodial: MPC wallets, no seed phrases
- •✅ Built-in Compliance: AML/KYC for enterprise users
Step-by-Step Flow
Step 1: User Authentication (Clerk)
typescript
// User signs in via Clerk UI component
// Clerk manages the entire auth flow
import { useAuth, useUser } from '@clerk/clerk-react';
const { isSignedIn, getToken } = useAuth();
const { user } = useUser();
// Wait for successful sign-in
if (isSignedIn && user) {
// Proceed to wallet initialization
const email = user.primaryEmailAddress?.emailAddress;
}
Step 2: Wallet Initialization (Crossmint)
typescript
import { CrossmintWalletProvider } from '@crossmint/client-sdk-react-ui';
// Crossmint automatically creates wallets on login
// No manual initialization required
<CrossmintWalletProvider createOnLogin={{
chain: 'solana:devnet', // Primary chain
signer: { type: 'email', email: user.email },
}}>
{children}
</CrossmintWalletProvider>
// Wallets created on ALL chains:
// - Solana (devnet/mainnet)
// - Ethereum, Base, Polygon, Arbitrum, Optimism
Step 3: Wallet Address Retrieval
typescript
import { useWallet } from '@crossmint/client-sdk-react-ui';
const { wallet } = useWallet();
// Get addresses for all chains
const addresses = {
solana: wallet.address, // Primary Solana address
ethereum: await wallet.getAddress('ethereum'),
base: await wallet.getAddress('base'),
polygon: await wallet.getAddress('polygon'),
};
Step 4: Database Sync (Supabase)
typescript
// Call Supabase edge function to sync wallet addresses
const response = await fetch(
`${SUPABASE_URL}/functions/v1/sync-crossmint-wallet`,
{
method: 'POST',
headers: {
'Content-Type': 'application/json',
'Authorization': `Bearer ${clerkToken}`,
},
body: JSON.stringify({
clerkUserId: user.id,
walletId: wallet.id,
addresses: addresses,
}),
}
);
// Edge function stores addresses in crossmint_wallets table
Database Schema
sql
CREATE TABLE crossmint_wallets ( id UUID PRIMARY KEY DEFAULT gen_random_uuid(), user_id UUID NOT NULL REFERENCES profiles(id), clerk_user_id TEXT NOT NULL, -- Crossmint wallet identifier crossmint_wallet_id TEXT UNIQUE NOT NULL, -- Multi-chain addresses solana_address TEXT, ethereum_address TEXT, base_address TEXT, polygon_address TEXT, arbitrum_address TEXT, optimism_address TEXT, -- Metadata wallet_type TEXT DEFAULT 'crossmint_embedded', created_at TIMESTAMPTZ DEFAULT NOW(), updated_at TIMESTAMPTZ DEFAULT NOW(), is_active BOOLEAN DEFAULT TRUE, CONSTRAINT unique_user_crossmint UNIQUE (user_id, clerk_user_id) ); -- Indexes for fast lookups CREATE INDEX idx_crossmint_wallets_clerk_user ON crossmint_wallets(clerk_user_id); CREATE INDEX idx_crossmint_wallets_solana ON crossmint_wallets(solana_address); CREATE INDEX idx_crossmint_wallets_ethereum ON crossmint_wallets(ethereum_address);
Supabase Edge Function
typescript
// supabase/functions/sync-crossmint-wallet/index.ts
import { serve } from 'https://deno.land/std@0.168.0/http/server.ts';
import { createClient } from 'https://esm.sh/@supabase/supabase-js@2';
serve(async (req) => {
const { clerkUserId, walletId, addresses } = await req.json();
// Initialize Supabase
const supabase = createClient(
Deno.env.get('SUPABASE_URL')!,
Deno.env.get('SUPABASE_SERVICE_ROLE_KEY')!
);
// Get user profile
const { data: profile } = await supabase
.from('profiles')
.select('id')
.eq('clerk_user_id', clerkUserId)
.single();
// Upsert wallet addresses
await supabase
.from('crossmint_wallets')
.upsert({
user_id: profile.id,
clerk_user_id: clerkUserId,
crossmint_wallet_id: walletId,
solana_address: addresses.solana,
ethereum_address: addresses.ethereum,
base_address: addresses.base,
polygon_address: addresses.polygon,
updated_at: new Date().toISOString(),
}, {
onConflict: 'clerk_user_id',
});
return new Response(JSON.stringify({ success: true }));
});
React Provider Setup
typescript
// src/providers/CrossmintProvider.tsx
import { CrossmintProvider, CrossmintAuthProvider, CrossmintWalletProvider } from '@crossmint/client-sdk-react-ui';
import { useAuth, useUser } from '@clerk/clerk-react';
export function AppCrossmintProvider({ children }) {
const { isSignedIn } = useAuth();
const { user } = useUser();
if (!isSignedIn || !user) {
return <>{children}</>;
}
return (
<CrossmintProvider apiKey={CROSSMINT_API_KEY}>
<CrossmintAuthProvider>
<CrossmintWalletProvider createOnLogin={{
chain: 'solana:devnet',
signer: { type: 'email', email: user.primaryEmailAddress.emailAddress },
}}>
{children}
</CrossmintWalletProvider>
</CrossmintAuthProvider>
</CrossmintProvider>
);
}
Complete Integration Guide
For comprehensive implementation details, see:
- •Plugin:
plugins/crossmint-fullstack/ - •Setup Command:
/crossmint:setup - •Wallet Flow Command:
/crossmint:create-wallet-flow - •Documentation:
docs/CROSSMINT_INTEGRATION_PLAN.md
Comparison to Previous Architecture
| Feature | Previous (Alchemy) | Current (Crossmint) |
|---|---|---|
| Chains Supported | Solana only | Solana + 50+ EVM chains |
| Wallet Creation | Manual per chain | Automatic multichain |
| Setup Complexity | Moderate | Simple (createOnLogin) |
| NFT Minting | External tools | Built-in API |
| Gas Sponsorship | Policy-based | Built-in |
| Enterprise Features | Limited | AML/KYC built-in |
Troubleshooting
Issue: Wallet not created after sign-in
- •Check Crossmint API key is valid
- •Verify
createOnLoginconfig is set - •Check browser console for errors
- •Ensure Clerk authentication completed
Issue: Addresses not syncing to database
- •Verify edge function deployed
- •Check edge function logs in Supabase dashboard
- •Ensure RLS policies allow wallet insertion
- •Validate Clerk token in edge function
Issue: Wrong chain addresses
- •Use
wallet.getAddress(chain)for specific chains - •Primary wallet.address is always Solana
- •Chain identifiers: 'ethereum', 'base', 'polygon', etc.
Next Steps
- •Install Crossmint SDK:
npm install @crossmint/client-sdk-react-ui - •Run setup wizard:
/crossmint:setup - •Generate wallet flow:
/crossmint:create-wallet-flow - •Deploy edge function:
supabase functions deploy sync-crossmint-wallet - •Test multichain wallet creation
References
- •Crossmint Documentation: https://docs.crossmint.com
- •Crossmint Fullstack Plugin:
plugins/crossmint-fullstack/ - •Clerk Documentation: https://clerk.com/docs
- •Supabase Edge Functions: https://supabase.com/docs/guides/functions