Files
meet-hub/supabase/migrations/20250102000001_auth_otp.sql
dwindown 0d29c953c1 Implement OTP-based email verification system
Add custom email verification using 6-digit OTP codes via Mailketing API:

Database:
- Create auth_otps table with 15-minute expiry
- Add indexes and RLS policies for security
- Add cleanup function for expired tokens
- Insert default auth_email_verification template

Edge Functions:
- send-auth-otp: Generate OTP, store in DB, send via Mailketing
- verify-auth-otp: Validate OTP, confirm email in Supabase Auth

Frontend:
- Add OTP input state to auth page
- Implement send/verify OTP in useAuth hook
- Add resend countdown timer (60 seconds)
- Update auth flow: signup → OTP verification → login

Features:
- Instant email delivery (no queue/cron)
- 6-digit OTP with 15-minute expiry
- Resend OTP with cooldown
- Admin-configurable email templates
- Indonesian UI text

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
2026-01-02 13:27:46 +07:00

69 lines
2.4 KiB
PL/PgSQL

-- ============================================================================
-- Auth OTP System - Email Verification with One-Time Passwords
-- ============================================================================
-- Create auth_otps table to store OTP codes for email verification
CREATE TABLE IF NOT EXISTS auth_otps (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
user_id UUID NOT NULL REFERENCES auth.users(id) ON DELETE CASCADE,
email TEXT NOT NULL,
otp_code TEXT NOT NULL,
expires_at TIMESTAMP WITH TIME ZONE NOT NULL,
used_at TIMESTAMP WITH TIME ZONE,
created_at TIMESTAMP WITH TIME ZONE DEFAULT NOW()
);
-- Create indexes for performance
CREATE INDEX IF NOT EXISTS idx_auth_otps_user_otp ON auth_otps(user_id, otp_code);
CREATE INDEX IF NOT EXISTS idx_auth_otps_expires_at ON auth_otps(expires_at);
CREATE INDEX IF NOT EXISTS idx_auth_otps_email ON auth_otps(email);
-- Enable RLS
ALTER TABLE auth_otps ENABLE ROW LEVEL SECURITY;
-- RLS Policies
-- Service role has full access
CREATE POLICY "Service role can do everything" ON auth_otps
FOR ALL
TO service_role
USING (true)
WITH CHECK (true);
-- Authenticated users can query their own OTPs
CREATE POLICY "Users can view own OTPs" ON auth_otps
FOR SELECT
TO authenticated
USING (auth.uid() = user_id);
-- Edge functions (via service role) can insert OTPs
CREATE POLICY "Service role can insert OTPs" ON auth_otps
FOR INSERT
TO service_role
WITH CHECK (true);
-- Edge functions (via service role) can update OTPs (mark as used)
CREATE POLICY "Service role can update OTPs" ON auth_otps
FOR UPDATE
TO service_role
USING (true)
WITH CHECK (true);
-- Function to clean up expired OTPs
CREATE OR REPLACE FUNCTION cleanup_expired_otps()
RETURNS void AS $$
BEGIN
DELETE FROM auth_otps
WHERE expires_at < NOW();
END;
$$ LANGUAGE plpgsql;
-- Comment on table
COMMENT ON TABLE auth_otps IS 'Stores OTP codes for email verification. Generated when users register, used to confirm email addresses.';
-- Comment on columns
COMMENT ON COLUMN auth_otps.user_id IS 'Reference to auth.users.id';
COMMENT ON COLUMN auth_otps.email IS 'Email address being verified (for redundancy)';
COMMENT ON COLUMN auth_otps.otp_code IS '6-digit OTP code';
COMMENT ON COLUMN auth_otps.expires_at IS 'OTP expiration time (typically 15 minutes)';
COMMENT ON COLUMN auth_otps.used_at IS 'When OTP was used (NULL if unused)';