firebase / firebase/firebase-js-sdk

linkWithPopup throws auth/multi-factor-auth-required after successful link, getMultiFactorResolver fails with auth/argument-error

Open
#9,467 1 comment 0 reactions 0 assignees View on GitHub
api: auth bug needs-attention reproducible
Dominant language
TypeScript
Stars
5.1k
Forks
1k
Avg merge
2d 21h
Merged PRs (30d)
37

Description

### Operating System

macOS (26.2 (25C56))

### Environment (if applicable)

Safari (Version 26.2 (21623.1.14.11.9))

### Firebase SDK Version

Tested on both 12.6.0 and 12.8.0 - same behavior

### Firebase SDK Product(s)

Auth

### Project Tooling

React SPA with Vite

### Detailed Problem Description

#### What I was trying to achieve
Link a federated provider (Microsoft) to an existing user account that has Phone MFA enabled, using `linkWithPopup()`.

#### What actually happened
1. `linkWithPopup()` throws `auth/multi-factor-auth-required` error
2. Attempting to handle the error with `getMultiFactorResolver(auth, error)` fails with `auth/argument-error`
3. However, checking `currentUser.providerData` reveals the provider WAS successfully linked

#### Console output (Firebase 12.8.0)

```
Error code: auth/multi-factor-auth-required
Error customData: {_serverResponse: Object, appName: "[DEFAULT]"}
Error serverResponse: {
federatedId: "http://microsoft.com/...",
providerId: "microsoft.com",
email: "user@example.com",
emailVerified: true
}
getMultiFactorResolver FAILED: "auth/argument-error"
Provider IDs after reload: ["microsoft.com", "password"]
Was linked: true
```

#### Key observations
- The `_serverResponse` contains the successfully linked federated identity, confirming the link completed on the
server
- The error doesn't contain valid MFA resolver information (hence `getMultiFactorResolver` fails)
- Same behavior on both 12.6.0 and 12.8.0

#### Expected behavior
Either:
1. `linkWithPopup()` should resolve successfully since the link completes, OR
2. If MFA verification is required, the error should contain valid resolver information

#### Current workaround
We reload the user and check if the provider was linked. This is brittle - if Firebase changes timing (throws error
before link completes), it would break.

#### Related
- FlutterFire #9402 - Similar issue fixed for Flutter SDK:
> "properly propagate the FirebaseAuthMultiFactorException for all reauthenticate and link methods"

#### Additional context
- Tested on localhost (127.0.0.1) development environment
- Not yet verified if the issue reproduces on production domains

### Steps and code to reproduce issue

```
// Prerequisites:
// 1. User account with email/password + Phone MFA enabled
// 2. User is signed in and has completed MFA verification

import { getAuth, getMultiFactorResolver, OAuthProvider, linkWithPopup } from 'firebase/auth';

const auth = getAuth();
const currentUser = auth.currentUser;
const provider = new OAuthProvider('microsoft.com');

try {
await linkWithPopup(currentUser, provider);
console.log('Link succeeded');
} catch (error) {
console.log('Error code:', error.code);
// Output: "auth/multi-factor-auth-required"

// Attempting to handle MFA as documented
try {
const resolver = getMultiFactorResolver(auth, error);
console.log('Resolver:', resolver);
} catch (mfaError) {
console.log('getMultiFactorResolver failed:', mfaError.code);
// Output: "auth/argument-error"
}

// Check if link actually succeeded despite the error
await currentUser.reload();
console.log('Provider IDs:', currentUser.providerData.map(p => p.providerId));
// Output: ["microsoft.com", "password"] - link DID succeed!
}
```

Contributor guide

Open the contributing guide

Assessment

This issue has not been assessed yet.

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.