Supabase OTP

This guide explains how to configure Supabase to send OTP tokens instead of magic links for email authentication.

When you request an email OTP, Supabase sends a magic link instead of a 6-digit OTP code. This happens because the default configuration prioritizes magic links over OTP codes.

🔧 Solution: Configure Supabase Project Settings

Step 1: Access Supabase Dashboard

  1. Go to https://supabase.com/dashboard

  2. Select your project.

  3. Navigate to AuthenticationSettings

Step 2: Configure Email Auth Settings

In the Auth Settings section:

  1. Find "Email OTP" Settings:

    • Look for "Email OTP" configuration

    • Enable "Email OTP" if it's disabled

  2. Disable Magic Links (if needed):

    • Look for "Magic Link" settings

    • Consider disabling magic links to force OTP usage

  3. Email Template Settings:

    • Go to AuthenticationEmail Templates

    • Select "Magic Link" template

    • Change the template type or configure it for OTP

Step 3: Alternative Approach - Use Explicit OTP Configuration

// In your API call, specify the type explicitly
const { data, error } = await supabase.auth.signInWithOtp({
    email: '[email protected]',
    options: {
        emailRedirectTo: undefined, // Don't set redirect URL for magic links
        shouldCreateUser: true
    }
});

📧 Email Template Configuration

Configure Email OTP Template

  1. Go to AuthenticationEmail Templates

  2. Select "Magic Link" or find "OTP" template

  3. Ensure the template contains {{ .Token }} instead of {{ .ConfirmationURL }}

Example OTP email template:

<h2>Your verification code</h2>
<p>Enter this code to verify your email:</p>
<h1>{{ .Token }}</h1>
<p>This code expires in 5 minutes.</p>

🔍 Troubleshooting

Check Current Configuration

Run this test to see what type of email you're receiving:

curl -X POST "https://auth-test.serverlessapigw.com/api/v1/supabase/auth" \
  -H "Content-Type: application/json" \
  -d '{"email": "[email protected]"}'
  1. Check Email Templates: Verify the template uses {{ .Token }} not {{ .ConfirmationURL }}

  2. Project Settings: Ensure OTP is enabled in Auth settings

  3. Cache: Clear browser cache and try again

  4. Different Email: Try with a different email address

Alternative Solution: Use Phone OTP

If email OTP continues to send magic links, use phone OTP instead:

curl -X POST "https://auth-test.serverlessapigw.com/api/v1/supabase/auth" \
  -H "Content-Type: application/json" \
  -d '{"phone": "+1234567890"}'

🧪 Testing After Configuration

Test Email OTP:

# Send OTP
curl -X POST "https://auth-test.serverlessapigw.com/api/v1/supabase/auth" \
  -H "Content-Type: application/json" \
  -d '{"email": "[email protected]"}'

# You should receive an email with a 6-digit code like: 123456
# Then verify with:
curl -X POST "https://auth-test.serverlessapigw.com/api/v1/supabase/verify" \
  -H "Content-Type: application/json" \
  -d '{"email": "[email protected]", "token": "123456"}'

📱 Enable SMS OTP (Optional)

If you want phone OTP:

  1. Go to AuthenticationSettings

  2. Find "Phone Auth" section

  3. Configure your SMS provider (Twilio, MessageBird, etc.)

  4. Enable phone authentication

🔧 Code-Level Fix (If Dashboard Doesn't Work)

If the dashboard configuration doesn't work, we can try a different approach in the code:

// Try using admin client with explicit OTP type
const supabase = createClient(
    process.env.SUPABASE_URL, 
    process.env.SUPABASE_SERVICE_ROLE_KEY  // Use service role key
);

const { data, error } = await supabase.auth.admin.generateLink({
    type: 'signup',  // or 'signin'
    email: email,
    options: {
        redirectTo: undefined  // No redirect for OTP
    }
});

📞 Need Help?

If you're still receiving magic links after following these steps:

  1. Check your Supabase project's Auth settings carefully

  2. Try creating a new test project to verify OTP behavior

  3. Contact Supabase support if the issue persists

  4. Consider using phone OTP as an alternative

Expected Behavior After Fix

After proper configuration:

  • Email OTP: You'll receive a 6-digit code like 123456

  • Response: API returns success message about OTP being sent

  • Verification: Use the 6-digit code to verify and get JWT tokens

The key is ensuring your Supabase project is configured to prioritize OTP codes over magic links in the authentication flow.

Last updated