Skip to content

OTP & 2FA Authentication System

ClawPlate provides a comprehensive OTP (One-Time Password) and 2FA (Two-Factor Authentication) system built on top of Supabase Auth. This feature enhances security by requiring users to verify their identity through multiple factors.

Overview

The OTP system supports multiple authentication methods:

  • Email OTP: 6-digit codes sent via email
  • SMS OTP: 6-digit codes sent via SMS (requires Supabase SMS configuration)
  • Magic Links: Passwordless authentication via email links
  • 2FA Integration: Two-factor authentication for enhanced security

Features

✅ Multi-Method Support

  • Email-based OTP verification
  • SMS-based OTP verification
  • Magic link authentication
  • Seamless integration with existing auth flow

✅ Enhanced Security

  • Time-limited codes (configurable expiration)
  • Rate limiting and cooldown periods
  • Secure code generation and validation
  • Protection against brute force attacks

✅ User Experience

  • Auto-submit on completion
  • Paste support for codes
  • Keyboard navigation (arrow keys, backspace)
  • Visual feedback (loading states, errors, success)
  • Responsive design for all devices

✅ Developer Friendly

  • TypeScript support
  • Composable architecture
  • Toast notifications
  • Error handling
  • Customizable UI components

Implementation Architecture

Core Components

├── composables/
│   ├── useAuth.ts              # Main authentication composable
│   └── useToast.ts             # Toast notification system
├── components/
│   ├── SupabaseOtpForm.vue     # OTP form component
│   └── OAuthButton.vue         # Social login buttons
└── pages/
    └── auth/
        ├── login.vue           # Login page with OTP integration
        └── callback.vue        # Auth callback handler

Authentication Flow

  1. Initial Authentication

    • User chooses between email/password or magic link
    • For magic link: OTP code is sent to email
    • For 2FA: OTP code is sent after successful password verification
  2. OTP Verification

    • 6-digit code input with real-time validation
    • Auto-submit when all digits are entered
    • Resend functionality with cooldown timer
  3. Session Management

    • Automatic session creation on successful verification
    • Redirect to intended destination
    • Persistent login options

Configuration

Supabase Setup

Ensure your Supabase project is configured for OTP:

sql
-- Enable OTP in your Supabase dashboard
-- Go to Authentication > Settings > Auth Providers
-- Enable "Enable email confirmations"
-- Configure email templates

Environment Variables

bash
# Required for OTP functionality
SUPABASE_URL=your_supabase_url
SUPABASE_ANON_KEY=your_supabase_anon_key

# Optional: For SMS OTP (requires Supabase SMS setup)
SUPABASE_SMS_PROVIDER=twilio  # or messagebird

Email Templates

Configure email templates in Supabase Dashboard:

  1. Magic Link Template
html
<h2>Sign in to {{ .SiteName }}</h2>
<p>Click this link to sign in:</p>
<p><a href="{{ .ConfirmationURL }}">Sign In</a></p>
<p>Or enter this code: <strong>{{ .Token }}</strong></p>
  1. OTP Code Template
html
<h2>Your verification code</h2>
<p>Your verification code is: <strong>{{ .Token }}</strong></p>
<p>This code will expire in 5 minutes.</p>

Usage Examples

Basic OTP Implementation

vue
<template>
  <div class="auth-container">
    <!-- Tab Selection -->
    <div class="auth-tabs">
      <button @click="activeTab = 'password'">Password</button>
      <button @click="activeTab = 'otp'">Magic Link</button>
    </div>

    <!-- OTP Form -->
    <SupabaseOtpForm 
      v-if="activeTab === 'otp'"
      type="email" 
      :redirect-to="/dashboard"
      @success="handleOtpSuccess"
      @error="handleOtpError"
    />
  </div>
</template>

<script setup lang="ts">
const activeTab = ref<'password' | 'otp'>('password')

const handleOtpSuccess = async (user: any, session: any) => {
  // Handle successful OTP verification
  console.log('User authenticated:', user)
  await navigateTo('/dashboard')
}

const handleOtpError = (error: string) => {
  // Handle OTP errors
  console.error('OTP Error:', error)
}
</script>

Advanced 2FA Integration

vue
<script setup lang="ts">
const { signIn, loading } = useAuth()
const { toast } = useToast()

// Step 1: Regular login
const handleEmailLogin = async () => {
  const result = await signIn(email, password)
  
  if (result.requires2FA) {
    // Show OTP form for 2FA
    show2FAForm.value = true
  } else if (result.success) {
    // Direct login success
    await navigateTo('/dashboard')
  }
}

// Step 2: 2FA verification
const handle2FAVerification = async (code: string) => {
  const result = await verify2FA(code)
  
  if (result.success) {
    await navigateTo('/dashboard')
  }
}
</script>

Security Considerations

Code Generation

  • Codes are cryptographically secure random numbers
  • 6-digit codes provide good balance of security and usability
  • Codes expire after 5 minutes by default

Rate Limiting

javascript
// Built-in Supabase rate limiting
// - 5 attempts per hour per email
// - Cooldown periods between resend requests
// - Automatic blocking of suspicious activity

Best Practices

  1. Always use HTTPS in production
  2. Implement proper error handling for network issues
  3. Use secure redirects to prevent open redirect attacks
  4. Log authentication events for security monitoring
  5. Implement session management with appropriate timeouts

API Reference

useAuth Composable

typescript
interface AuthComposable {
  // OTP Methods
  sendOTP(email: string, type: 'email' | 'sms'): Promise<AuthResult>
  verifyOTP(email: string, code: string): Promise<AuthResult>
  
  // Magic Link Methods
  sendMagicLink(email: string, redirectTo?: string): Promise<AuthResult>
  
  // 2FA Methods
  enable2FA(): Promise<AuthResult>
  disable2FA(): Promise<AuthResult>
  verify2FA(code: string): Promise<AuthResult>
  
  // State
  loading: Ref<boolean>
  user: Ref<User | null>
  session: Ref<Session | null>
}

Events

The OTP system emits several events for integration:

typescript
interface OTPEvents {
  'submit': (code: string) => void      // Code submitted
  'resend': () => void                  // Resend requested
  'complete': (code: string) => void    // Code completed
  'change': (code: string) => void      // Code changed
  'error': (message: string) => void    // Error occurred
  'success': (user: User) => void       // Success
}

Customization

Styling

The OTP components use Tailwind CSS classes and can be customized:

vue
<SupabaseOtpForm 
  class="custom-otp-form"
  :input-class="custom-input-style"
  :button-class="custom-button-style"
/>

Behavior

vue
<SupabaseOtpForm 
  :length="8"              // 8-digit codes instead of 6
  :auto-submit="false"     // Disable auto-submit
  :resend-cooldown="60"    // 60 second cooldown
  :use-toast="false"       // Disable toast notifications
/>

Testing

Unit Tests

javascript
// Test OTP code validation
describe('OTP Validation', () => {
  test('validates 6-digit codes', () => {
    expect(isValidOTP('123456')).toBe(true)
    expect(isValidOTP('12345')).toBe(false)
    expect(isValidOTP('1234567')).toBe(false)
  })
})

Integration Tests

javascript
// Test OTP flow
describe('OTP Authentication Flow', () => {
  test('sends OTP and verifies code', async () => {
    // Send OTP
    const sendResult = await sendOTP('test@example.com')
    expect(sendResult.success).toBe(true)
    
    // Verify OTP (in real tests, you'd get this from email)
    const verifyResult = await verifyOTP('test@example.com', '123456')
    expect(verifyResult.success).toBe(true)
  })
})

Troubleshooting

Common Issues

  1. Codes not received

    • Check email spam/junk folders
    • Verify email configuration in Supabase
    • Check rate limiting settings
  2. Invalid code errors

    • Ensure code hasn't expired (5 minute limit)
    • Check for typos in email address
    • Verify Supabase configuration
  3. Resend cooldown issues

    • Implement proper cooldown UI feedback
    • Check rate limiting configuration
    • Consider implementing progressive delays

Debug Mode

Enable debug logging for development:

javascript
// In your nuxt.config.ts
export default defineNuxtConfig({
  runtimeConfig: {
    public: {
      authDebug: process.env.NODE_ENV === 'development'
    }
  }
})

Production Deployment

Checklist

  • [ ] Configure email templates in Supabase
  • [ ] Set up proper domain verification
  • [ ] Configure SMTP settings (if using custom provider)
  • [ ] Test OTP flow in production environment
  • [ ] Monitor authentication metrics
  • [ ] Set up error alerting

Monitoring

Track these metrics in production:

  • OTP success/failure rates
  • Average verification time
  • Resend request frequency
  • Failed attempt patterns
  • Session duration after OTP verification

Support

For issues related to OTP functionality:

  1. Check Supabase Auth logs
  2. Verify email delivery status
  3. Review rate limiting settings
  4. Test with different email providers
  5. Contact support with specific error messages

The OTP system provides a secure, user-friendly authentication method that enhances your application's security while maintaining excellent user experience.

Built with love by mhdevfr