Fix: Implement auth.resend() for email confirmation

This commit is contained in:
gpt-engineer-app[bot]
2025-10-14 17:06:10 +00:00
parent 32fc2b583d
commit e8a7c028e9

View File

@@ -213,50 +213,56 @@ export async function addPasswordToAccount(
}; };
} }
// Step 1: Update password AND trigger email confirmation // Step 1: Set the password (does NOT create email identity yet)
// Re-confirming the email will trigger Supabase to create the email identity console.log('[IdentityService] Setting password');
console.log('[IdentityService] Setting password and triggering email confirmation'); const { error: updateError } = await supabase.auth.updateUser({ password });
const { error: updateError } = await supabase.auth.updateUser({
password,
email: userEmail // Re-confirm email to create email identity provider
});
if (updateError) throw updateError; if (updateError) throw updateError;
// Step 2: Get user profile for email personalization // Step 2: Trigger signup confirmation email (this creates the email identity)
console.log('[IdentityService] Fetching user profile for email'); console.log('[IdentityService] Sending signup confirmation email');
const { error: resendError } = await supabase.auth.resend({
type: 'signup',
email: userEmail,
options: {
emailRedirectTo: `${window.location.origin}/auth?confirmed=password-setup`
}
});
if (resendError) {
console.error('[IdentityService] Failed to send confirmation email:', resendError);
throw resendError;
}
// Step 3: Get user profile for custom notification email
console.log('[IdentityService] Fetching user profile');
const { data: profile } = await supabase const { data: profile } = await supabase
.from('profiles') .from('profiles')
.select('display_name, username') .select('display_name, username')
.eq('user_id', user!.id) .eq('user_id', user!.id)
.single(); .single();
// Step 3: Send password addition email (before logging out) // Step 4: Send our custom "Password Added" notification (informational)
console.log('[IdentityService] Sending password addition email'); console.log('[IdentityService] Sending custom notification email');
try { try {
const { error: emailError } = await supabase.functions.invoke('send-password-added-email', { await supabase.functions.invoke('send-password-added-email', {
body: { body: {
email: userEmail, email: userEmail,
displayName: profile?.display_name, displayName: profile?.display_name,
username: profile?.username, username: profile?.username,
}, },
}); });
if (emailError) {
console.error('[IdentityService] Failed to send email:', emailError);
} else {
console.log('[IdentityService] Email sent successfully');
}
} catch (emailError) { } catch (emailError) {
console.error('[IdentityService] Email sending error:', emailError); console.error('[IdentityService] Custom email failed (non-blocking):', emailError);
} }
// Step 4: Log the password addition // Step 5: Log the action
await logIdentityChange(user!.id, 'password_added', { await logIdentityChange(user!.id, 'password_added', {
method: 'oauth_with_email_confirmation_required' method: 'oauth_password_addition_with_signup_confirmation',
confirmation_email_sent: true
}); });
// Step 5: Sign the user out so they can confirm email // Step 6: Sign user out (they must confirm via email)
console.log('[IdentityService] Signing user out to complete email confirmation'); console.log('[IdentityService] Signing user out');
await supabase.auth.signOut(); await supabase.auth.signOut();
// Return success with relogin and email confirmation flags // Return success with relogin and email confirmation flags
@@ -306,45 +312,49 @@ export async function triggerOrphanedPasswordConfirmation(
}; };
} }
console.log('[IdentityService] Triggering email confirmation for orphaned password'); console.log('[IdentityService] Resending signup confirmation email');
// Step 1: Get user profile for email personalization // Send Supabase signup confirmation email
const { error: resendError } = await supabase.auth.resend({
type: 'signup',
email: user.email,
options: {
emailRedirectTo: `${window.location.origin}/auth?confirmed=password-confirmation`
}
});
if (resendError) {
console.error('[IdentityService] Failed to resend confirmation:', resendError);
throw resendError;
}
console.log('[IdentityService] Confirmation email resent successfully');
// Optional: Get profile for custom notification
const { data: profile } = await supabase const { data: profile } = await supabase
.from('profiles') .from('profiles')
.select('display_name, username') .select('display_name, username')
.eq('user_id', user.id) .eq('user_id', user.id)
.single(); .single();
// Step 2: Send password confirmation email via edge function // Optional: Send custom notification email (non-blocking)
console.log('[IdentityService] Invoking send-password-added-email edge function'); try {
const { data: emailData, error: emailError } = await supabase.functions.invoke( await supabase.functions.invoke('send-password-added-email', {
'send-password-added-email',
{
body: { body: {
email: user.email, email: user.email,
displayName: profile?.display_name, displayName: profile?.display_name,
username: profile?.username, username: profile?.username,
}, },
} });
); } catch (emailError) {
console.error('[IdentityService] Custom email failed (non-blocking):', emailError);
if (emailError) {
console.error('[IdentityService] Edge function invocation failed:', emailError);
throw new Error(emailError.message || 'Failed to send confirmation email');
} }
if (emailData && !emailData.success) { // Log the action
console.error('[IdentityService] Edge function returned error:', emailData.error);
throw new Error(emailData.error || 'Email service returned an error');
}
console.log('[IdentityService] Confirmation email sent successfully');
// Step 3: Log the action for audit trail
await logIdentityChange(user.id, 'orphaned_password_confirmation_triggered', { await logIdentityChange(user.id, 'orphaned_password_confirmation_triggered', {
method: source || 'manual_button_click', method: source || 'manual_button_click',
timestamp: new Date().toISOString(), timestamp: new Date().toISOString(),
email_sent: true confirmation_email_sent: true
}); });
return { return {