Skip to content

OTP Authentication in MakerKit

Commercial License Required

MakerKit requires a commercial license. While Orchestre can help you build with it, you must obtain a valid license from MakerKit for commercial use.

Overview

MakerKit v2.11.0 introduces a powerful OTP (One-Time Password) authentication system through the @kit/otp package. This feature enables secure verification for critical actions and can be used alongside traditional authentication methods.

Key Features

  • Magic Link Authentication: Passwordless login via email
  • Action Verification: Secure critical operations with OTP
  • Flexible Integration: Works with existing auth systems
  • Built-in Security: Rate limiting and expiration handling

Architecture

The OTP system is built on:

  • @kit/otp package for core functionality
  • Supabase for storage and delivery
  • Email provider integration for sending codes
  • Redis for rate limiting (optional)

Implementation Patterns

Replace traditional password login with OTP:

typescript
import { createOtpApi } from '@kit/otp/api';
import { getSupabaseServerClient } from '@kit/supabase/server-client';

// Create OTP instance
const client = getSupabaseServerClient();
const otpApi = createOtpApi(client);

// Send magic link
await otpApi.sendOtp({
  email: 'user@example.com',
  type: 'magiclink',
  redirectTo: '/dashboard'
});

2. Action Verification

Protect sensitive operations:

typescript
// Before critical action
const { data: otp } = await otpApi.sendOtp({
  email: user.email,
  type: 'verification',
  action: 'delete-account'
});

// Verify OTP before proceeding
const { data: verified } = await otpApi.verifyOtp({
  email: user.email,
  token: userProvidedOtp,
  type: 'verification'
});

if (verified) {
  // Proceed with critical action
}

3. Multi-Factor Authentication Integration

Combine with TOTP for enhanced security:

typescript
// After password verification
if (user.mfaEnabled) {
  // Send OTP as additional factor
  await otpApi.sendOtp({
    email: user.email,
    type: 'mfa',
    userId: user.id
  });
  
  // Redirect to OTP verification page
  return redirect('/auth/verify-otp');
}

Configuration

Environment Variables

bash
# Email provider settings
EMAIL_FROM=noreply@yourapp.com
EMAIL_PROVIDER=resend # or sendgrid, postmark

# OTP settings
OTP_EXPIRATION_MINUTES=10
OTP_MAX_ATTEMPTS=3

Database Schema

The OTP system uses Supabase's built-in auth schema with additional metadata:

sql
-- OTP attempts tracking (optional)
CREATE TABLE auth.otp_attempts (
  id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
  email VARCHAR(255) NOT NULL,
  ip_address INET,
  attempted_at TIMESTAMP WITH TIME ZONE DEFAULT NOW(),
  success BOOLEAN DEFAULT FALSE
);

-- Index for performance
CREATE INDEX idx_otp_attempts_email ON auth.otp_attempts(email);

Using with Orchestre

Recipe Prompt

Use the dedicated recipe prompt to implement OTP:

bash
/template recipe-otp-verification

This will:

  1. Set up the OTP infrastructure
  2. Create verification flows
  3. Add UI components
  4. Configure email templates
  5. Implement rate limiting

Manual Integration

For custom implementations:

  1. Install dependencies:

    bash
    npm install @kit/otp
  2. Create API routes:

    typescript
    // app/api/auth/otp/send/route.ts
    export async function POST(request: Request) {
      const { email, type } = await request.json();
      const client = getSupabaseServerClient();
      const otpApi = createOtpApi(client);
      
      const result = await otpApi.sendOtp({ email, type });
      return Response.json(result);
    }
  3. Add verification UI:

    tsx
    // app/auth/verify-otp/page.tsx
    import { OtpVerificationForm } from '@kit/otp/components';
    
    export default function VerifyOtpPage() {
      return <OtpVerificationForm />;
    }

Best Practices

Security Considerations

  1. Rate Limiting: Implement per-email and per-IP limits
  2. Expiration: Use short expiration times (5-10 minutes)
  3. Single Use: Ensure OTPs can only be used once
  4. Secure Transport: Always use HTTPS
  5. Audit Logging: Track OTP usage for security monitoring

UX Guidelines

  1. Clear Instructions: Explain why OTP is needed
  2. Resend Option: Allow users to request new codes
  3. Countdown Timer: Show expiration time
  4. Error Messages: Provide helpful feedback
  5. Alternative Methods: Offer backup verification options

Common Patterns

Progressive Security

typescript
// Low-risk actions: No OTP
await updateProfile({ name: newName });

// Medium-risk: OTP for email changes
if (isChangingEmail) {
  await requireOtpVerification();
}

// High-risk: OTP + password
if (isDeletingAccount) {
  await requirePasswordAndOtp();
}

Custom OTP Templates

typescript
// Customize email templates
const otpApi = createOtpApi(client, {
  emailTemplate: {
    subject: (otp) => `Your ${otp.type} code: ${otp.code}`,
    html: (otp) => customOtpEmailTemplate(otp),
    text: (otp) => `Your verification code is: ${otp.code}`
  }
});

Troubleshooting

Common Issues

  1. OTP Not Received:

    • Check email provider configuration
    • Verify sender domain authentication
    • Check spam folders
  2. Invalid OTP Error:

    • Ensure correct expiration settings
    • Check timezone handling
    • Verify database time sync
  3. Rate Limit Errors:

    • Adjust rate limit thresholds
    • Implement exponential backoff
    • Add CAPTCHA for repeated attempts

Integration with Other Features

  • Team Invitations: Use OTP for secure invite acceptance
  • Billing Changes: Require OTP for payment method updates
  • API Key Generation: Verify identity before creating keys
  • Data Exports: Secure sensitive data access

Next Steps

Built with ❤️ for the AI Coding community, by Praney Behl