Skip to content

initializeAuth is not idempotent #8891

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

Open
jhuleatt opened this issue Apr 2, 2025 · 1 comment
Open

initializeAuth is not idempotent #8891

jhuleatt opened this issue Apr 2, 2025 · 1 comment

Comments

@jhuleatt
Copy link
Contributor

jhuleatt commented Apr 2, 2025

Operating System

n/a

Environment (if applicable)

n/a

Firebase SDK Version

11.6.0

Firebase SDK Product(s)

Auth

Project Tooling

Next.js

Detailed Problem Description

getAuth is idempotent, but initializeAuth is not. This causes issues with hot reloads while editing a Next.js app.

Steps and code to reproduce issue

Use initializeAuth in a Next.js app. Start the dev server, use initializeAuth, and see it error.

@jhuleatt jhuleatt added new A new issue that hasn't be categoirzed as question, bug or feature request question labels Apr 2, 2025
@jbalidiong jbalidiong added Repro Needed needs-attention and removed new A new issue that hasn't be categoirzed as question, bug or feature request labels Apr 2, 2025
@Davileal
Copy link

Davileal commented May 4, 2025

Hey @jhuleatt

After reviewing the source code, I noticed that initializeAuth() is intentionally non-idempotent when different parameters are passed (e.g., a different persistence array or popupRedirectResolver). In those cases, the SDK throws an expected exception to avoid inconsistent Auth behavior:

// packages/auth/src/core/auth/initialize.ts
export function initializeAuth(app: FirebaseApp, deps?: Dependencies): Auth {
  const provider = _getProvider(app, 'auth');

  if (provider.isInitialized()) {
    const auth = provider.getImmediate() as AuthImpl;
    const initialOptions = provider.getOptions() as Dependencies;
    if (deepEqual(initialOptions, deps ?? {})) {
      return auth;
    } else {
      _fail(auth, AuthErrorCode.ALREADY_INITIALIZED);
    }
  }

  const auth = provider.initialize({ options: deps }) as AuthImpl;

  return auth;
}

There are dedicated unit tests confirming this design. For example, this test explicitly verifies that re-calling initializeAuth() with a different persistence order will throw:

// packages/auth/src/core/auth/initialize.test.ts
it('should throw if called again with different params (persistence)', () => {
  initializeAuth(fakeApp, {
    persistence: [inMemoryPersistence, fakeSessionPersistence]
  });
  expect(() =>
    initializeAuth(fakeApp, {
      persistence: [fakeSessionPersistence, inMemoryPersistence]
    })
  ).to.throw();
});

To better understand this, I also created a minimal Next.js app using initializeAuth(), and I only observed the error after changing the configuration parameters (e.g. switching the order of persistence strategies) during a hot reload. If the parameters remain exactly the same, no error occurs. Did the error occur for you even without changing the initializeAuth configuration? I’d be happy to help contribute to that if needed.

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

4 participants