diff --git a/supabase/functions/cancel-email-change/index.ts b/supabase/functions/cancel-email-change/index.ts index d4d32b27..7750befc 100644 --- a/supabase/functions/cancel-email-change/index.ts +++ b/supabase/functions/cancel-email-change/index.ts @@ -5,6 +5,20 @@ const corsHeaders = { 'Access-Control-Allow-Headers': 'authorization, x-client-info, apikey, content-type', }; +// Helper function to decode JWT and extract user ID +function decodeJWT(token: string): { sub: string } | null { + try { + const parts = token.split('.'); + if (parts.length !== 3) return null; + + const payload = JSON.parse(atob(parts[1])); + return payload; + } catch (error) { + console.error('JWT decode error:', error); + return null; + } +} + Deno.serve(async (req) => { // Handle CORS preflight requests if (req.method === 'OPTIONS') { @@ -32,47 +46,39 @@ Deno.serve(async (req) => { } const token = authHeader.replace('Bearer ', ''); - console.log('Attempting to verify user token...'); + console.log('Extracting user ID from JWT token...'); - const { data: { user }, error: userError } = await supabaseAdmin.auth.getUser(token); - - if (userError) { - console.error('Token verification failed:', userError); - throw new Error('Invalid or expired session. Please refresh the page and try again.'); + // Parse JWT token to get user ID directly + const payload = decodeJWT(token); + if (!payload || !payload.sub) { + console.error('Invalid JWT token structure'); + throw new Error('Invalid session token. Please refresh the page and try again.'); } - if (!user) { - console.error('No user found for token'); - throw new Error('User not found. Please refresh the page and try again.'); - } - - console.log(`Cancelling email change for user ${user.id}`, { - currentEmail: user.email, - newEmail: user.new_email - }); + const userId = payload.sub; + console.log(`Cancelling email change for user ${userId}`); // Call the database function to clear email change fields // This function has SECURITY DEFINER privileges to access auth.users const { data: cancelled, error: cancelError } = await supabaseAdmin - .rpc('cancel_user_email_change', { _user_id: user.id }); + .rpc('cancel_user_email_change', { _user_id: userId }); if (cancelError || !cancelled) { console.error('Error cancelling email change:', cancelError); throw new Error('Unable to cancel email change: ' + (cancelError?.message || 'Unknown error')); } - console.log(`Successfully cancelled email change for user ${user.id}`); + console.log(`Successfully cancelled email change for user ${userId}`); // Log the cancellation in admin_audit_log const { error: auditError } = await supabaseAdmin .from('admin_audit_log') .insert({ - admin_user_id: user.id, - target_user_id: user.id, + admin_user_id: userId, + target_user_id: userId, action: 'email_change_cancelled', details: { cancelled_at: new Date().toISOString(), - current_email: user.email, }, }); @@ -86,8 +92,8 @@ Deno.serve(async (req) => { success: true, message: 'Email change cancelled successfully', user: { - id: user.id, - email: user.email, + id: userId, + email: null, new_email: null, }, }),