This guide explains how to migrate from custom email verification to Supabase Auth.
- Custom email verification with tokens
- Password stored in database (hashed)
- Custom JWT tokens
- Nodemailer for sending emails
- Supabase handles email verification
- Passwords managed by Supabase
- Supabase session tokens
- Supabase sends verification emails
password- Now handled by Supabase Authemail_verification_token- Supabase handles verificationemail_verification_expires- Supabase handles expirationis_email_verified- Check via Supabase Auth
supabase_user_id(UUID) - Links to Supabase Auth user
- Go to your Supabase project dashboard
- Navigate to Authentication → Settings
- Configure email templates (optional)
- Get your credentials:
- Project URL
- Anon Key
- Service Role Key
# Supabase Configuration
SUPABASE_URL=https://your-project.supabase.co
SUPABASE_ANON_KEY=your-anon-key
SUPABASE_SERVICE_ROLE_KEY=your-service-role-keycd backend
npm run migrateThis will:
- Add
supabase_user_idcolumn - Remove
password,email_verification_token,email_verification_expires - Add necessary indexes
Before:
POST /api/auth/register
{
"email": "[email protected]",
"password": "password123",
"firstName": "John",
"lastName": "Doe",
"role": "REQUESTER"
}
Response:
{
"message": "Registration successful. Please check your email...",
"userId": "uuid"
}After:
POST /api/auth/register
{
"email": "[email protected]",
"password": "password123",
"firstName": "John",
"lastName": "Doe",
"role": "REQUESTER"
}
Response:
{
"message": "Registration successful. Please check your email...",
"userId": "uuid",
"supabaseUserId": "supabase-uuid"
}Before:
POST /api/auth/login
{
"email": "[email protected]",
"password": "password123"
}
Response:
{
"message": "Login successful",
"token": "jwt-token",
"user": { ... }
}After:
POST /api/auth/login
{
"email": "[email protected]",
"password": "password123"
}
Response:
{
"message": "Login successful",
"session": {
"access_token": "supabase-token",
"refresh_token": "refresh-token",
"expires_in": 3600
},
"user": { ... }
}Before:
POST /api/auth/verify-email
{
"token": "verification-token"
}After:
Supabase handles this automatically via email link.
The callback URL is: ${FRONTEND_URL}/auth/callback
cd frontend
npm install @supabase/supabase-js// frontend/src/lib/supabase.ts
import { createClient } from '@supabase/supabase-js';
const supabaseUrl = import.meta.env.VITE_SUPABASE_URL;
const supabaseAnonKey = import.meta.env.VITE_SUPABASE_ANON_KEY;
export const supabase = createClient(supabaseUrl, supabaseAnonKey);// frontend/src/lib/api.ts
import { supabase } from './supabase';
class ApiClient {
async register(data: RegisterData) {
// Register with Supabase
const { data: authData, error } = await supabase.auth.signUp({
email: data.email,
password: data.password,
options: {
data: {
first_name: data.firstName,
last_name: data.lastName,
role: data.role,
},
},
});
if (error) throw error;
// Also create record in your backend
return this.request('/auth/register', {
method: 'POST',
body: JSON.stringify(data),
});
}
async login(data: LoginData) {
const { data: authData, error } = await supabase.auth.signInWithPassword({
email: data.email,
password: data.password,
});
if (error) throw error;
// Store session
if (authData.session) {
this.setToken(authData.session.access_token);
}
return authData;
}
async logout() {
await supabase.auth.signOut();
this.clearToken();
}
}// frontend/src/pages/AuthCallback.tsx
import { useEffect } from 'react';
import { useNavigate } from 'react-router-dom';
import { supabase } from '@/lib/supabase';
export default function AuthCallback() {
const navigate = useNavigate();
useEffect(() => {
supabase.auth.onAuthStateChange((event, session) => {
if (event === 'SIGNED_IN') {
navigate('/dashboard');
}
});
}, [navigate]);
return <div>Verifying email...</div>;
}// frontend/src/App.tsx
<Route path="/auth/callback" element={<AuthCallback />} />- Built-in Email Verification - No need to manage tokens
- Secure Password Storage - Handled by Supabase
- Session Management - Automatic token refresh
- Social Auth Ready - Easy to add Google, GitHub, etc.
- Rate Limiting - Built-in protection
- Email Templates - Customizable in dashboard
- MFA Support - Can enable 2FA easily
- Audit Logs - Track auth events
curl -X POST http://localhost:5000/api/auth/register \
-H "Content-Type: application/json" \
-d '{
"email": "[email protected]",
"password": "password123",
"firstName": "Test",
"lastName": "User",
"role": "REQUESTER"
}'User receives email from Supabase with verification link.
curl -X POST http://localhost:5000/api/auth/login \
-H "Content-Type: application/json" \
-d '{
"email": "[email protected]",
"password": "password123"
}'curl -X GET http://localhost:5000/api/auth/profile \
-H "Authorization: Bearer <supabase-access-token>"- Check Supabase dashboard → Authentication → Email Templates
- Verify SMTP settings (if using custom SMTP)
- Check spam folder
- Verify email redirect URL is correct
- Check token hasn't expired (default 1 hour)
- Use refresh token to get new access token
- Verify Supabase URL and keys are correct
- Ensure user record created in both Supabase Auth and your database
- Check
supabase_user_idmatches - Verify migration ran successfully
If you need to rollback:
cd backend
npm run migrate:undoThis will restore the old schema with password and email verification fields.
- Supabase Docs: https://supabase.com/docs/guides/auth
- Supabase Discord: https://discord.supabase.com/
🚚 DropIt - Now powered by Supabase Auth