The wizard prompts for your backend choice and credentials, then configures apps/app/.env automatically.Without credentials: The app runs in mock mode with simulated auth. Connect a real backend before production to test email confirmation, password reset, and OAuth flows.
Supabase: Updates user_metadata in Auth and syncs to profiles table
Convex: Updates the users table via mutation
The updateProfile action handles the backend differences automatically. Use firstName/lastName or fullName - it normalizes appropriately for each backend.
Social Login
Copy
const { signInWithGoogle, signInWithApple } = useAuth()// Google - uses native SDK on mobile, OAuth on webconst handleGoogleSignIn = async () => { const { error } = await signInWithGoogle() if (error) console.error('Google sign in error:', error)}// Apple - uses OAuth PKCEconst handleAppleSignIn = async () => { const { error } = await signInWithApple() if (error) console.error('Apple sign in error:', error)}
For magic links to work on web, configure redirect URLs in Supabase Dashboard → Authentication → URL Configuration → Redirect URLs:
Copy
# Local developmenthttp://localhost:3000/auth/callback # Vite webhttp://localhost:19006/auth/callback # Expo web# Production (replace with your domain)https://yourdomain.com/auth/callback
The app automatically uses the current origin for redirect URLs, so you just need to whitelist them in Supabase. On mobile, users enter the OTP code manually instead of clicking a link.
Add these environment variables to your Convex deployment:
Copy
RESEND_API_KEY=re_xxxxx # From resend.comRESEND_FROM_EMAIL=noreply@yourdomain.comAPP_NAME=YourApp
Domain Verification: You must verify your sending domain in Resend before emails will deliver. During development, use onboarding@resend.dev as the from address.
To delete data from third-party services, add secrets to Supabase:
Copy
npx supabase secrets set REVENUECAT_API_KEY=sk_your_secret_keynpx supabase secrets set POSTHOG_API_KEY=phx_your_personal_api_keynpx supabase secrets set POSTHOG_PROJECT_ID=12345
Account deletion calls a Convex action:
Copy
// In your componentimport { useAction } from '@/hooks/convex'import { api } from '@convex/_generated/api'const deleteAccount = useAction(api.users.deleteAccount)const handleDelete = async () => { await deleteAccount()}
Copy
// convex/users.tsexport const deleteAccount = action({ handler: async (ctx) => { const identity = await ctx.auth.getUserIdentity() if (!identity) throw new Error('Not authenticated') // Delete user data from your tables await ctx.runMutation(internal.users.deleteUserData, { userId: identity.subject, }) // Optional: Delete from RevenueCat, PostHog, etc. },})
In Supabase Dashboard → SQL Editor, run the contents of supabase/schema.sql. This creates the profiles, user_preferences, and push_tokens tables with RLS policies.See Backend Guide for schema customization.
RLS policies are pre-configured in the schema. auth.uid() returns the current user’s ID.
Copy
-- Users can only access their own datacreate policy "Users access own data" on profiles for all using (auth.uid() = id);-- Public read, authenticated writecreate policy "Anyone can read" on posts for select using (true);create policy "Users create own posts" on posts for insert with check (auth.uid() = author_id);