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/otppackage for core functionality- Supabase for storage and delivery
- Email provider integration for sending codes
- Redis for rate limiting (optional)
Implementation Patterns
1. Magic Link Authentication
Replace traditional password login with OTP:
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:
// 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:
// 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
# Email provider settings
EMAIL_FROM=noreply@yourapp.com
EMAIL_PROVIDER=resend # or sendgrid, postmark
# OTP settings
OTP_EXPIRATION_MINUTES=10
OTP_MAX_ATTEMPTS=3Database Schema
The OTP system uses Supabase's built-in auth schema with additional metadata:
-- 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:
/template recipe-otp-verificationThis will:
- Set up the OTP infrastructure
- Create verification flows
- Add UI components
- Configure email templates
- Implement rate limiting
Manual Integration
For custom implementations:
Install dependencies:
bashnpm install @kit/otpCreate 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); }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
- Rate Limiting: Implement per-email and per-IP limits
- Expiration: Use short expiration times (5-10 minutes)
- Single Use: Ensure OTPs can only be used once
- Secure Transport: Always use HTTPS
- Audit Logging: Track OTP usage for security monitoring
UX Guidelines
- Clear Instructions: Explain why OTP is needed
- Resend Option: Allow users to request new codes
- Countdown Timer: Show expiration time
- Error Messages: Provide helpful feedback
- Alternative Methods: Offer backup verification options
Common Patterns
Progressive Security
// 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
// 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
OTP Not Received:
- Check email provider configuration
- Verify sender domain authentication
- Check spam folders
Invalid OTP Error:
- Ensure correct expiration settings
- Check timezone handling
- Verify database time sync
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
- Explore the recipe-otp-verification prompt
- Review security patterns
- Check best practices
