capacitor-firebase
capacitor-firebase copied to clipboard
bug: getCurrentUser() returns null
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:
- Create a React
<IonApp>
wrapped in<AuthenticationProvider>
- Sign in with the
signInWithEmailAndPassword()
React hook - 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>
)
}
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();
}
...
It looks like there hasn't been a reply in 30 days, so I'm closing this issue.