Fix orphaned password state

This commit is contained in:
gpt-engineer-app[bot]
2025-10-14 15:07:27 +00:00
parent d44e47f177
commit 41757096c8
2 changed files with 87 additions and 3 deletions

View File

@@ -223,9 +223,16 @@ export function SecurityTab() {
<CardHeader> <CardHeader>
<CardDescription> <CardDescription>
{hasPassword ? ( {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 && (
<span className="block mt-2 text-amber-600 dark:text-amber-400">
If you've previously set a password but don't see it here, click "Add Password" to re-verify your authentication.
</span>
)}
</>
)} )}
</CardDescription> </CardDescription>
</CardHeader> </CardHeader>

View File

@@ -189,6 +189,7 @@ async function waitForEmailProvider(maxRetries = 6): Promise<boolean> {
/** /**
* Add password authentication to an OAuth-only account * Add password authentication to an OAuth-only account
* Also handles re-creating email identity for orphaned passwords
*/ */
export async function addPasswordToAccount( export async function addPasswordToAccount(
password: string 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 }); const { error } = await supabase.auth.updateUser({ password });
if (error) throw error; if (error) throw error;
@@ -217,6 +218,34 @@ export async function addPasswordToAccount(
const emailCreated = await waitForEmailProvider(); const emailCreated = await waitForEmailProvider();
if (!emailCreated) { 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 { return {
success: false, success: false,
error: 'Password was set but email provider verification failed. Please refresh the page and try signing in with your email and password.' 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<boolean> {
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<IdentityOperationResult> {
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 * Log identity changes to audit log
*/ */