capacitor-firebase icon indicating copy to clipboard operation
capacitor-firebase copied to clipboard

bug: getCurrentUser() returns null

Open mailinger-mate opened this issue 2 years ago • 1 comments

Plugin(s): "@capacitor-firebase/authentication": "^1.0.0"

Platform(s): Web

Current behavior: After succesfully authenticating with signInWithEmailAndPassword() the getCurrentUser() call returns { user: null }, despite the API call returning the user:

POST https://identitytoolkit.googleapis.com/v1/accounts:lookup?key=**
{
  "kind": "identitytoolkit#GetAccountInfoResponse",
  "users": [
    {
      "localId": "qYZ5erFyNUNGCTeNqAAot82Fd213",
      "email": "mate@**",
     }
     ...
}

Expected behavior: The getCurrentUser() call should return the user as receveid from the API when reloading the web app.

Steps to reproduce:

  1. Create a React <IonApp> wrapped in <AuthenticationProvider>
  2. Sign in with the signInWithEmailAndPassword() React hook
  3. Reload the web app to trigger getting the current user

Related code: AuthenticationProvider.tsx

interface Context {
    user: User | undefined;
    signInWithEmailAndPassword: (email: string, password: string) => void;
}

const app = initializeApp({...});
getAnalytics(app);

const AuthenticationContext = React.createContext<Context>({
    user: undefined,
    signInWithEmailAndPassword: () => undefined,
});

export const useAuthenticationContext = () => React.useContext(AuthenticationContext);

const AuthenticationProvider: React.FC = (props) => {
    const [user, setUser] = React.useState<User | undefined>(undefined);

    const signInWithEmailAndPassword = (
        email: string,
        password: string,
    ) => {
        FirebaseAuthentication
            .signInWithEmailAndPassword({ email, password })
            .then(result => {
                if (result.user) setUser(result.user);
            });
    };

    React.useEffect(() => {
        FirebaseAuthentication
            .getCurrentUser()
            .then((value => {
                if (value.user) setUser(value.user);
            }));
    }, [user]);

    const context: Context = {
        user,
        signInWithEmailAndPassword,
    };

    return (
        <AuthenticationContext.Provider value={context}>
            {props.children}
        </AuthenticationContext.Provider>
    );
};

export default AuthenticationProvider;

UserAuthentication.tsx

const UserAuthentication: React.FC = () => {
    const { user, signInWithEmailAndPassword } = useAuthenticationContext();
    const [email, setEmail] = React.useState<string | null | undefined>(user?.email);
    const [password, setPassword] = React.useState<string | null | undefined>(user?.email);

    const submit = React.useCallback(async () => {
        if (!email || !password) return;
        signInWithEmailAndPassword(email, password);
    }, [email, password]);

    return (
        <IonList>
            <IonItem>
                <IonLabel position="floating">Email</IonLabel>
                <IonInput
                    type="email"
                    required={true}
                    value={email}
                    onIonChange={e => setEmail(e.detail.value!)}
                />
            </IonItem>
            <IonItem>
                <IonLabel position="floating">Password</IonLabel>
                <IonInput
                    type="password"
                    value={password}
                    onIonChange={e => setPassword(e.detail.value!)}
                />
            </IonItem>
            <IonButton
                expand="full"
                onClick={submit}
            >
                Sign in
            </IonButton>
        </IonList>
    )
}

mailinger-mate avatar Sep 25 '22 03:09 mailinger-mate

After a page reload Firebase needs a short time to load the current auth state. You can use the authStateChange listener to get notified.

For example, this is a code snippet (Angular + rxjs) I use in my apps:

...

@Injectable({
  providedIn: 'root',
})
export class FirebaseAuthenticationService {
  private currentUserSubject = new ReplaySubject<User | undefined>(1);

  constructor(private readonly firebaseAppService: FirebaseAppService) {
    this.firebaseAppService.initializeApp();
    setPersistence(getAuth(), browserLocalPersistence);
    FirebaseAuthentication.addListener('authStateChange', result => {
      this.currentUserSubject.next(result.user || undefined);
    });
  }

  public getCurrentUser(): Promise<User | undefined> {
    return this.currentUser$.pipe(take(1)).toPromise();
  }

...

robingenz avatar Sep 25 '22 07:09 robingenz

It looks like there hasn't been a reply in 30 days, so I'm closing this issue.

github-actions[bot] avatar Oct 26 '22 01:10 github-actions[bot]