diff --git a/src/components/settings/SecurityTab.tsx b/src/components/settings/SecurityTab.tsx
index 7efd12f8..5413c482 100644
--- a/src/components/settings/SecurityTab.tsx
+++ b/src/components/settings/SecurityTab.tsx
@@ -223,9 +223,16 @@ export function SecurityTab() {
{hasPassword ? (
- <>Update your password to keep your account secure. {user?.identities?.some(i => i.provider === 'totp') && 'Two-factor authentication will be required.'}>
+ <>Update your password to keep your account secure.>
) : (
- 'Add password authentication to your account for increased security and backup access.'
+ <>
+ Add password authentication to your account for increased security and backup access.
+ {identities.length > 0 && (
+
+ If you've previously set a password but don't see it here, click "Add Password" to re-verify your authentication.
+
+ )}
+ >
)}
diff --git a/src/lib/identityService.ts b/src/lib/identityService.ts
index 4fc09fec..f9bc6e62 100644
--- a/src/lib/identityService.ts
+++ b/src/lib/identityService.ts
@@ -189,6 +189,7 @@ async function waitForEmailProvider(maxRetries = 6): Promise {
/**
* Add password authentication to an OAuth-only account
+ * Also handles re-creating email identity for orphaned passwords
*/
export async function addPasswordToAccount(
password: string
@@ -202,7 +203,7 @@ export async function addPasswordToAccount(
};
}
- // Update user with password
+ // Update user with password (works for both new and existing passwords)
const { error } = await supabase.auth.updateUser({ password });
if (error) throw error;
@@ -217,6 +218,34 @@ export async function addPasswordToAccount(
const emailCreated = await waitForEmailProvider();
if (!emailCreated) {
+ // Password was set but identity verification failed
+ // Try one more aggressive approach: sign in with the new password
+ console.log('[IdentityService] Attempting sign-in to trigger identity creation');
+
+ const { data: { user } } = await supabase.auth.getUser();
+ if (user?.email) {
+ // Attempt to sign in (this might create the identity)
+ const { error: signInError } = await supabase.auth.signInWithPassword({
+ email: user.email,
+ password: password
+ });
+
+ if (!signInError) {
+ // Sign-in successful, check identities again
+ const retriedEmailCreated = await waitForEmailProvider(2); // Quick retry
+ if (retriedEmailCreated) {
+ console.log('[IdentityService] Email provider created after sign-in');
+
+ // Log audit event
+ await logIdentityChange(user.id, 'password_added', {
+ method: 'oauth_fallback_with_signin_retry'
+ });
+
+ return { success: true };
+ }
+ }
+ }
+
return {
success: false,
error: 'Password was set but email provider verification failed. Please refresh the page and try signing in with your email and password.'
@@ -241,6 +270,54 @@ export async function addPasswordToAccount(
}
}
+/**
+ * Check if user has an orphaned password (password exists but no email identity)
+ */
+export async function hasOrphanedPassword(): Promise {
+ const identities = await getUserIdentities();
+ const hasEmailIdentity = identities.some(i => i.provider === 'email');
+
+ if (hasEmailIdentity) return false;
+
+ // If user has OAuth identities but no email identity, they might have an orphaned password
+ return identities.length > 0 && !hasEmailIdentity;
+}
+
+/**
+ * Re-verify password authentication by attempting sign-in
+ * This forces Supabase to create the email identity if it's missing
+ */
+export async function reverifyPasswordAuth(
+ email: string,
+ password: string
+): Promise {
+ try {
+ const { error } = await supabase.auth.signInWithPassword({
+ email,
+ password
+ });
+
+ if (error) throw error;
+
+ // Check if email identity was created
+ const emailCreated = await waitForEmailProvider(3);
+
+ if (!emailCreated) {
+ return {
+ success: false,
+ error: 'Sign-in successful but identity verification failed. Please contact support.'
+ };
+ }
+
+ return { success: true };
+ } catch (error: any) {
+ return {
+ success: false,
+ error: error.message || 'Failed to verify password authentication'
+ };
+ }
+}
+
/**
* Log identity changes to audit log
*/