-- ============================================================================ -- 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)';