How to fix otp_disabled: OTP sign-in is disabled in Supabase

SupabaseBEGINNERMEDIUMUpdated Dec 15, 2025ยท 236 views

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.

Quick fix

Fixes otp_disabled

<h2>Your verification code</h2>
<p>Enter this code in your application:</p>
<h1>{{ .Token }}</h1>
<p>This code expires in 1 hour.</p>
  1. Enable Email OTP in Supabase Dashboard
  2. Configure Email Templates for OTP
  3. Enable Phone OTP Provider (if using phone authentication)
  4. Update your application code to use signInWithOtp correctly
supabase โ€” error
<h2>Your verification code</h2>
<p>Enter this code in your application:</p>
<h1>{{ .Token }}</h1>
<p>This code expires in 1 hour.</p>
otp_disabled: OTP sign-in is disabled

What this error means

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

Typical symptoms

  • User sign-in attempts fail with 'otp_disabled' error code
  • Authentication requests return 400 Bad Request status
  • Console shows 'OTP sign-in is disabled' error message
  • signInWithOtp() method throws an error immediately
  • Users don't receive OTP codes via email or SMS
  • Authentication flow fails before reaching email/SMS sending stage

Common causes

  1. Email OTP provider not enabled in Supabase dashboard (most common)
  2. Phone/SMS OTP provider not enabled when using phone authentication
  3. SMS provider (Twilio, MessageBird, etc.) not configured for phone OTP
  4. Email templates configured for magic links instead of OTP tokens
  5. Authentication settings changed after initial setup
  6. Using wrong authentication method (magic link vs OTP) in code
  7. Project authentication providers were disabled for security review

How to fix "otp_disabled: OTP sign-in is disabled"

1Enable Email OTP in Supabase Dashboard

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.

2Configure Email Templates for OTP

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:

html
<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

3Enable Phone OTP Provider (if using phone authentication)

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:

bash
Account SID: ACxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
Auth Token: your_auth_token_here
Phone Number: +1234567890
4Update your application code to use signInWithOtp correctly

Verify your authentication code is properly calling the OTP method:

For email OTP (JavaScript/TypeScript):

javascript
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: 'user@example.com',
  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:

javascript
// Send OTP to phone
const { data, error } = await supabase.auth.signInWithOtp({
  phone: '+1234567890',
  options: {
    shouldCreateUser: true,
  }
})

Verify the OTP:

javascript
const { data, error } = await supabase.auth.verifyOtp({
  email: 'user@example.com', // or phone: '+1234567890'
  token: '123456', // The 6-digit code user entered
  type: 'email' // or 'sms' for phone
})
5Test the OTP authentication flow

Test your OTP configuration end-to-end:

1. Send a test OTP to yourself:

javascript
const { error } = await supabase.auth.signInWithOtp({
     email: 'your-email@example.com'
   })
   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:

javascript
const { data, error } = await supabase.auth.verifyOtp({
     email: 'your-email@example.com',
     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

6Verify Site URL and Redirect URL configuration

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:

bash
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.

Advanced notes

### 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:

html
<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.

Frequently asked questions

What does "otp_disabled" mean?
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.
How do I fix "otp_disabled"?
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.
What causes "otp_disabled"?
Email OTP provider not enabled in Supabase dashboard (most common) Phone/SMS OTP provider not enabled when using phone authentication SMS provider (Twilio, MessageBird, etc.) not configured for phone OTP
Is the "otp_disabled" error serious?
It is a medium-severity error โ€” more of a blocker than a risk. The steps above resolve it.

Official resources & further reading