This Supabase Authentication error occurs when you attempt to use one-time password (OTP) authentication without enabling it in your project settings. The fix requires enabling email or phone OTP providers in the Supabase dashboard and properly configuring your authentication flow.
The "otp_disabled" error in Supabase Authentication indicates that your application is trying to use the `signInWithOtp()` method for passwordless authentication, but the OTP authentication method hasn't been enabled for your Supabase project. Supabase supports passwordless authentication through one-time passwords (OTPs) sent via email or SMS. However, these authentication methods must be explicitly enabled in your project's authentication settings before they can be used. By default, while email authentication is enabled, the specific OTP method (as opposed to magic links) may require additional configuration. This error commonly appears when: 1. You're using `signInWithOtp()` in your code without enabling the OTP provider 2. You've disabled email or phone providers in the Supabase dashboard 3. You're trying to use phone/SMS OTP without configuring an SMS provider 4. You've configured email templates to use magic links instead of OTP tokens 5. Your project configuration has changed and OTP was inadvertently disabled
Navigate to your Supabase project and enable email OTP:
1. Go to the [Supabase Dashboard](https://app.supabase.com/)
2. Select your project
3. In the left sidebar, click Authentication > Providers
4. Find the Email provider section
5. Ensure the Enable Email provider toggle is ON
6. Scroll down to Email OTP Expiration settings
7. Configure OTP expiration time (default is 1 hour)
8. Click Save to apply changes
Note: Email authentication methods, including Email OTPs, are typically enabled by default, but verify this setting if you're encountering the error.
Ensure your email templates are set up to send OTP codes:
1. In Supabase Dashboard, go to Authentication > Email Templates
2. Select the template type you want to use (Confirm signup, Magic Link, etc.)
3. Edit the template to include the {{ .Token }} variable for OTP codes
Example OTP email template:
<h2>Your verification code</h2>
<p>Enter this code in your application:</p>
<h1>{{ .Token }}</h1>
<p>This code expires in 1 hour.</p>Important: If you want to use OTPs instead of magic links, modify the magic link template to display the {{ .Token }} variable instead of {{ .ConfirmationURL }}.
4. Click Save to apply template changes
If you're using phone/SMS authentication, configure the phone provider:
1. In Supabase Dashboard > Authentication > Providers
2. Find the Phone provider section
3. Toggle Enable Phone provider to ON
4. Select an SMS provider from the dropdown:
- Twilio (recommended for production)
- MessageBird
- Vonage
- TextLocal
5. Enter your SMS provider credentials:
- For Twilio: Account SID, Auth Token, and phone number
- For other providers: Follow their specific setup instructions
6. Configure phone OTP settings:
- OTP expiration time
- Rate limiting
- Template message
7. Click Save
Example Twilio configuration:
Account SID: ACxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
Auth Token: your_auth_token_here
Phone Number: +1234567890Verify your authentication code is properly calling the OTP method:
For email OTP (JavaScript/TypeScript):
import { createClient } from '@supabase/supabase-js'
const supabase = createClient('YOUR_SUPABASE_URL', 'YOUR_ANON_KEY')
// Send OTP to email
const { data, error } = await supabase.auth.signInWithOtp({
email: '[email protected]',
options: {
// Should create user if they don't exist (default: true)
shouldCreateUser: true,
}
})
if (error) {
console.error('Error sending OTP:', error.message)
} else {
console.log('OTP sent successfully!')
}For phone OTP:
// Send OTP to phone
const { data, error } = await supabase.auth.signInWithOtp({
phone: '+1234567890',
options: {
shouldCreateUser: true,
}
})Verify the OTP:
const { data, error } = await supabase.auth.verifyOtp({
email: '[email protected]', // or phone: '+1234567890'
token: '123456', // The 6-digit code user entered
type: 'email' // or 'sms' for phone
})Test your OTP configuration end-to-end:
1. Send a test OTP to yourself:
const { error } = await supabase.auth.signInWithOtp({
email: '[email protected]'
})
console.log('OTP sent:', !error)2. Check your email/phone:
- Verify you receive the OTP code
- Check the code format (should be 6 digits)
- Note the expiration time
3. Verify the OTP code:
const { data, error } = await supabase.auth.verifyOtp({
email: '[email protected]',
token: '123456', // Code from email
type: 'email'
})
if (data.user) {
console.log('User authenticated:', data.user.email)
}4. Check rate limiting:
- By default, users can only request an OTP once every 60 seconds
- Verify error handling for rate-limited requests
5. Monitor in Supabase Dashboard:
- Go to Authentication > Users to see newly authenticated users
- Check Logs for any authentication errors
Ensure your site URLs are properly configured:
1. In Supabase Dashboard > Authentication > URL Configuration
2. Set your Site URL to your application's URL:
- Production: https://yourapp.com
- Development: http://localhost:3000
3. Add Redirect URLs for allowed redirect destinations:
- Add all URLs where users should be redirected after authentication
- Include both development and production URLs
Example configuration:
Site URL: https://yourapp.com
Redirect URLs:
- https://yourapp.com/auth/callback
- http://localhost:3000/auth/callback
- yourapp://auth/callback (for mobile apps)Note: While OTP authentication doesn't always require redirects (unlike magic links), proper URL configuration is essential for the overall authentication flow.
### Understanding OTP vs Magic Link Authentication
Supabase supports two types of passwordless authentication:
1. Magic Links: Users click a link in their email to authenticate. The link contains a token and redirects to your app.
2. OTP (One-Time Password): Users receive a 6-digit code via email/SMS and manually enter it in your app. No redirect required.
Key differences:
- Magic links require redirect URL configuration; OTPs don't
- OTPs work better for mobile apps and native experiences
- Magic links are simpler for users (one click vs typing code)
- OTPs provide more control over the authentication UI
### Email Template Configuration
The same email template system handles both magic links and OTPs. The template variables determine which method is used:
- {{ .ConfirmationURL }}: Creates a magic link
- {{ .Token }}: Displays a 6-digit OTP code
You can customize templates to include both:
<p>Click this link: <a href="{{ .ConfirmationURL }}">Verify Email</a></p>
<p>Or enter this code: <strong>{{ .Token }}</strong></p>### Rate Limiting and Security
Supabase implements rate limiting to prevent abuse:
- Default rate limit: 1 OTP request per 60 seconds per email/phone
- Configurable: Adjust in Dashboard > Authentication > Rate Limits
- OTP expiration: Default 1 hour, configurable per provider
Security best practices:
- Always validate OTPs on the server side
- Implement additional rate limiting in your application
- Monitor authentication logs for suspicious patterns
- Use CAPTCHA for public sign-up forms
- Consider enabling email confirmation for new accounts
### SMS Provider Selection
For phone OTP, choose an SMS provider based on your needs:
Twilio:
- Most popular and reliable
- Global coverage
- ~$0.0075 per SMS (US)
- Excellent deliverability
MessageBird:
- Good European coverage
- Competitive pricing
- Strong compliance features
Vonage (formerly Nexmo):
- Good for high-volume applications
- Advanced analytics
- Global presence
TextLocal:
- Best for UK/India markets
- Cost-effective for regional use
### Troubleshooting Common Issues
OTP emails going to spam:
- Configure custom SMTP in Dashboard > Project Settings > SMTP
- Use a verified sending domain
- Adjust email template to avoid spam triggers
Phone OTP not delivering:
- Verify SMS provider credentials
- Check phone number format (must include country code: +1234567890)
- Ensure sufficient SMS provider credits
- Check carrier restrictions (some carriers block automated messages)
Rate limiting issues:
- Implement exponential backoff in your client code
- Show clear error messages to users
- Consider increasing rate limits for trusted users
### Migration from Magic Links to OTP
If migrating from magic links to OTPs:
1. Update email templates to include {{ .Token }}
2. Change client code from magic link handling to OTP verification
3. Update user documentation and onboarding
4. Consider supporting both methods during transition
5. Test thoroughly with different email clients
### Multi-factor Authentication (MFA)
OTP can be used as part of a multi-factor authentication strategy:
- Combine password login with OTP verification
- Use phone OTP as a second factor after email authentication
- Implement time-based OTP (TOTP) for enhanced security
Note: Supabase also supports TOTP-based MFA through separate methods.
email_conflict_identity_not_deletable: Cannot delete identity because of email conflict
How to fix "Cannot delete identity because of email conflict" in Supabase
mfa_challenge_expired: MFA challenge has expired
How to fix "mfa_challenge_expired: MFA challenge has expired" in Supabase
conflict: Database conflict, usually related to concurrent requests
How to fix "database conflict usually related to concurrent requests" in Supabase
phone_exists: Phone number already exists
How to fix "phone_exists" in Supabase
StorageApiError: resource_already_exists
StorageApiError: Resource already exists