Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Firebase Auth Emulator doesn't work with TOTP MFA secret generation #6224

Open
konvoulgaris opened this issue Aug 5, 2023 · 10 comments
Open

Comments

@konvoulgaris
Copy link

[REQUIRED] Environment info

firebase-tools: 12.4.7

Platform: Ubuntu 22.04.2 LTS (WSL)

[REQUIRED] Test case

Assume a button that generates a secret in any web app and calls the below function when clicked:

const handleMFEnable = async () => {
    try {
        await reauthenticateWithPopup(user, authGoogleProvider);
        const mfSession = await multiFactor(user).getSession();
        const mfSecret = await TotpMultiFactorGenerator.generateSecret(mfSession);
        const mfUri = await mfSecret.generateQrCodeUrl(user.email, "Test App");
        console.log(mfUri);
    } catch (error) {
        console.error(error);
    }
}

[REQUIRED] Steps to reproduce

Running everything exactly as the docs describe:

  • Enabling Auth with Identity Platform
  • Enabling TOTP MFA using the REST API
  • Reauthenticating the User
  • Generating TOTP secret

[REQUIRED] Expected behavior

It should print the the secret URI in order to display the QR for the user to scan. This operating should be the identical whether auth is emulated or live.

[REQUIRED] Actual behavior

When running under the Auth emulator, the following error appears client-side:

FirebaseError: Firebase: ((Missing phoneEnrollmentInfo.)) (auth/invalid-argument).
    at _errorWithCustomMessage (assert.ts:100:18)
    at _performFetchWithErrorHandling (index.ts:193:15)
    at async TotpMultiFactorGenerator.generateSecret (totp.ts:97:22)
    at async handleMFEnable (Account.tsx?t=1691256036484:146:24)

However, when disabling the Auth emulator and running everything with the live service, everything works as expected.

Reference Add TOTP multi-factor authentication to your web app

@christhompsongoogle
Copy link
Contributor

Currently the Auth emulator doesn't support TOTP MFA. Internal bug: b/288313571

@jakehockey10
Copy link

@christhompsongoogle are there any links I can check out or other discussions to read through on this topic as TOTP pertains to emulated environments? I'd like to learn more about it so I can anticipate if and when this will be supported. Thanks!

@joehan
Copy link
Contributor

joehan commented Jan 16, 2024

Hey @jakehockey10, unfortunately, we can't make any promises to support this in the auth emulator anytime soon.

@mandalornl
Copy link

@jakehockey10 We simple add a custom claim (e.g. emulator) as a temporary workaround to skip TOTP validation. Mind you, only when using the emulator suite.

rules_version = '2';
service cloud.firestore {
  match /databases/{database}/documents {
    function hasAuthToken(claim) {
      return request.auth.token.get(claim, false) == true;
    }

    function isLoggedIn() {
      return request.auth != null
        && (
          hasAuthToken('emulator')
          || (
            request.auth.token.firebase.get('sign_in_second_factor', null) == 'totp'
            && 'second_factor_identifier' in request.auth.token.firebase
          )
        );
    }

    function isAdmin() {
      return isLoggedIn() && hasAuthToken('admin');
    }

    match /users/{id} {
      allow read: if true;
      allow write: if isAdmin();
    }
}
import { initializeApp } from 'firebase/app';
import { 
  getAuth,
  connectAuthEmulator,
  authStateReady,
  onAuthStateChanged,
  getIdTokenResult
} from 'firebase/auth';

const app = initializeApp({
// your config
});
const auth = getAuth(app);

if (process.env.FIREBASE_EMULATOR) {
  connectAuthEmulator(auth, 'http://localhost:9099', {
    disableWarnings: true
  });
}

await firebase.auth.authStateReady();

onAuthStateChanged(auth, async (authUser) => {
  const idTokenResult = authUser ? await getIdTokenResult(authUser) : null;
  
  if (
    idTokenResult?.signInSecondFactor !== 'totp' 
    && !idTokenResult?.claims?.emulator
  ) {
    return;
  }
  
  // do something
});

@jakehockey10
Copy link

Hey @jakehockey10, unfortunately, we can't make any promises to support this in the auth emulator anytime soon.

No worries! Wasn't anticipating any promises or anything. Just didn't know if there was plans for it documented any where or if it wasn't really that far along yet. Thanks for the response!

@jakehockey10
Copy link

@jakehockey10 We simple add a custom claim (e.g. emulator) as a temporary workaround to skip TOTP validation. Mind you, only when using the emulator suite.

rules_version = '2';
service cloud.firestore {
  match /databases/{database}/documents {
    function hasAuthToken(claim) {
      return request.auth.token.get(claim, false) == true;
    }

    function isLoggedIn() {
      return request.auth != null
        && (
          hasAuthToken('emulator')
          || (
            request.auth.token.firebase.get('sign_in_second_factor', null) == 'totp'
            && 'second_factor_identifier' in request.auth.token.firebase
          )
        );
    }

    function isAdmin() {
      return isLoggedIn() && hasAuthToken('admin');
    }

    match /users/{id} {
      allow read: if true;
      allow write: if isAdmin();
    }
}
import { initializeApp } from 'firebase/app';
import { 
  getAuth,
  connectAuthEmulator,
  authStateReady,
  onAuthStateChanged,
  getIdTokenResult
} from 'firebase/auth';

const app = initializeApp({
// your config
});
const auth = getAuth(app);

if (process.env.FIREBASE_EMULATOR) {
  connectAuthEmulator(auth, 'http://localhost:9099', {
    disableWarnings: true
  });
}

await firebase.auth.authStateReady();

onAuthStateChanged(auth, async (authUser) => {
  const idTokenResult = authUser ? await getIdTokenResult(authUser) : null;
  
  if (
    idTokenResult?.signInSecondFactor !== 'totp' 
    && !idTokenResult?.claims?.emulator
  ) {
    return;
  }
  
  // do something
});

Thank you so much for your response! This approach makes a lot of sense and I appreciate you sharing your insight!

@mikehardy
Copy link

I'm looking into implementing TOTP functionality soon in react-native-firebase on top of the android + ios native SDKs, and our current e2e testing infrastructure relies on the auth emulator, as it doesn't have the rate-limiting issues we were running into when running e2e in CI against "real" / cloud auth APIs.

Would love to see the TOTP functionality supported in the emulator 🙏 , otherwise the cloud APIs are the only alternative and we'll be subject to CI flakiness related to the rate limits the cloud auth APIs implement

That's a lot of words for basically a "👍" but if it helps raise priority it is worth it 😄

Cheers

@elucidsoft
Copy link

How is this still not fixed nearly a year has gone by?

@elucidsoft
Copy link

Been nearly 2 years now and you still don't support this most basic feature in the emulator. But you guys added AI support, which nobody cares about.

@mikehardy
Copy link

@elucidsoft you'd be surprised the excitement amongst library consumers for the AI support, so I'd be careful generalizing your own preferences into an assertion of what people care about or not. There is demonstrated demand for AI support.

Also, TOTP / MFA support is likely not "the most basic feature", otherwise I'd expect to see a PR from you with just a few + lines and boom! we're set, right?

That said, I would dearly love to see this feature implemented - please please - as the react-native-firebase maintainer this pops up from time to time as we don't support TOTP yet, and one of the reasons is that we converted our e2e test suite to use the emulator exclusively (so we don't hit rate limits on lots of the real-cloud-APIs we need to test...) but...then we have no test support for the TOTP APIs which makes it hard to implement.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

8 participants