Email + Password Authentication
Email/password is the traditional authentication method. Users create an account with their email and a password they choose.
Consider your use case. For subscription apps with paywalls, anonymous auth often converts better. Email auth adds friction before users see your app’s value.
Overview
Email authentication is the simplest to set up:
- Supabase Dashboard — Enable Email provider (usually already enabled)
- Your App — Use the pre-built forms and auth functions
Time required: ~10 minutes
Part 1: Supabase Configuration
Enable Email Provider
Open Auth settings
Go to your Supabase project dashboardNavigate to Authentication → Providers
Check Email is enabled
Find Email in the listIt should be enabled by default. If not, toggle it on.
Open Email Templates
Go to Authentication → Email Templates
Customize templates
You can customize:
- Confirm signup — Email sent when user signs up
- Reset password — Email sent when user requests password reset
- Magic link — Email for passwordless login (if enabled)
Each template supports variables like {{ .ConfirmationURL }}
Security Settings (Optional)
Go to Authentication → Settings to configure:
| Setting | Recommendation |
|---|
| Confirm email | Enable for production (prevents fake signups) |
| Secure email change | Enable (requires confirmation for email changes) |
| Min password length | 8+ characters recommended |
Part 2: App Configuration
Step 1: Enable in App Config
Update config/app.config.ts:
auth: {
mode: 'required', // Users must sign in
providers: {
email: true, // Enable email/password
apple: false,
google: false,
},
}
Step 2: Use Auth Functions
The kit provides these email auth functions in lib/auth.ts:
import { signInWithEmail, signUpWithEmail, resetPassword } from '@/lib/auth';
// Sign in existing user
await signInWithEmail('user@example.com', 'password123');
// Create new account
await signUpWithEmail('user@example.com', 'password123');
// Send password reset email
await resetPassword('user@example.com');
Step 3: Use Pre-built Screens
Navigate to the auth screens:
import { useRouter } from 'expo-router';
const router = useRouter();
// Go to login
router.push('/auth/login');
// Go to signup
router.push('/auth/signup');
// Go to forgot password
router.push('/auth/forgot-password');
Using the Components
import { LoginForm } from '@/components/auth';
<LoginForm
onSuccess={() => {
// User signed in successfully
router.replace('/(main)');
}}
onForgotPassword={() => {
router.push('/auth/forgot-password');
}}
onSignUp={() => {
router.push('/auth/signup');
}}
/>
import { SignupForm } from '@/components/auth';
<SignupForm
onSuccess={() => {
// Account created - user needs to verify email
Alert.alert(
'Check your email',
'We sent you a confirmation link.'
);
}}
onLogin={() => {
router.push('/auth/login');
}}
/>
import { ForgotPasswordForm } from '@/components/auth';
<ForgotPasswordForm
onSuccess={() => {
// Email sent
Alert.alert('Email sent', 'Check your inbox for reset instructions.');
}}
onBack={() => {
router.back();
}}
/>
Email Verification Flow
When email confirmation is enabled (recommended for production):
- User signs up with email/password
- Supabase sends confirmation email
- User clicks link in email
- User is verified and can sign in
Handling Unverified Users
import { useAuth } from '@/contexts/auth-context';
const { user } = useAuth();
// Check if email is confirmed
if (user && !user.email_confirmed_at) {
// Show "Please verify your email" message
}
The kit includes a reusable AuthInput component:
import { AuthInput } from '@/components/auth';
<AuthInput
label="Email"
placeholder="you@example.com"
icon="mail-outline"
value={email}
onChangeText={setEmail}
keyboardType="email-address"
autoComplete="email"
/>
<AuthInput
label="Password"
placeholder="Enter password"
icon="lock-closed-outline"
value={password}
onChangeText={setPassword}
secureTextEntry // Shows eye toggle for password visibility
autoComplete="password"
error={passwordError} // Shows error message below input
/>
Combining with Social Auth
You can offer both email and social authentication:
import { AuthDivider, LoginForm, SocialAuthButtons } from '@/components/auth';
// In your login screen
<SocialAuthButtons
showApple={true}
showGoogle={true}
onSuccess={handleSuccess}
/>
<AuthDivider text="or sign in with email" />
<LoginForm
onSuccess={handleSuccess}
onForgotPassword={() => router.push('/auth/forgot-password')}
/>
Error Handling
Common errors and how to handle them:
| Error | Meaning | User Message |
|---|
Invalid login credentials | Wrong email or password | ”Invalid email or password” |
User already registered | Email already exists | ”An account with this email already exists” |
Password should be at least X characters | Password too short | ”Password must be at least X characters” |
Email not confirmed | User hasn’t verified email | ”Please verify your email first” |
The LoginForm and SignupForm components handle these automatically.
Testing
In Development
- Sign up with a real email you can access
- Check your inbox for the confirmation email
- Click the link to verify
- Sign in with your credentials
Test Accounts
For testing without real emails, you can:
- Disable email confirmation in Supabase (development only)
- Use Supabase’s Inbucket for local email testing
Next Steps