auth().currentUser.reload() returns undefined - firebase

I am trying to check firebase emailVerified without logging out the user (Angular 6 web app), but auth().currentUser.reload() returns "undefined"
Tried:
import { auth } from 'firebase/app';
auth().currentUser.reload().then((u) => {
console.log(u);
});
Tried:
import { AngularFireAuth } from '#angular/fire/auth';
this.afAuth.auth.currentUser.reload().then((u) => {
console.log(u);
});
These related issues DO NOT HELP.
Update the email verification status without reloading page
Firebase: Observe email verification status in real time
Auth.auth().currentUser?.reload() doesn't refresh currentUser.isEmailVerified

The firebase core doesn't include the auth module. You need to add the auth module:
import firebase from 'firebase/app';
import 'firebase/auth';
If no user is currently authenticated, currentUser will be null and will not have a reload() function. Trying to call it would give you and error.
The reload() function returns a promise so you can use .then, but the promise doesn't return the currentUser object. To view the currentUser after the reload, just refer to the currentUser...
if (firebase.auth().currentUser) {
firebase.auth().currentUser.reload().then(() => {
console.log(JSON.stringify(firebase.auth().currentUser));
});
} else {
console.log('No authenticated user');
}

Related

listUsers is not a function error in Firebase Authentication

I'm trying to fetch a list of all the users in my web app, but I keep receiving this error:
"TypeError: utils_firebase_WEBPACK_IMPORTED_MODULE_2_.auth.listUsers is not a function"
I copied exactly from Firebase documentation, and below is my code.
auth prints out "AuthImpl {app: FirebaseAppImpl, heartbeatServiceProvider: Provider, config: {…}, currentUser: null, emulatorConfig: null, …}", so I know that auth exists.
import { useEffect } from "react";
import { auth } from "../utils/firebase";
function users() {
const listAllUsers = (nextPageToken) => {
console.log(auth);
auth
.listUsers(1000, nextPageToken)
.then((listUsersResult) => {
listUsersResult.users.forEach((userRecord) => {
console.log("user", userRecord);
});
if (listUsersResult.pageToken) {
listAllUsers(listUsersResult.pageToken);
}
})
.catch((error) => {
console.log("Error listing users:", error);
});
};
useEffect(() => {
listAllUsers();
}, []);
return <div>users</div>;
}
export default users;
Can someone help me with this? Thanks!
I tried to look at the documentation from Firebase, but with no luck
listUsers() is a method from the Admin SDK and not from the JS SDK. The page you copied the code from documents the Admin SDK methods for the Authentication Service.
There isn't any corresponding method in the JS SDK because, for security reasons, it is not possible to let a user directly listing all users of a Firebase project from a front-end.
If you want to list all users of your Firebase project from your front-end you can write a Callable Cloud Function that uses the listUsers() Admin SDK's method. It's then up to you to verify who can call this Cloud Function.

Firebase Authentication JS does not populate `providerData`array

in a VueJS / QuasarJS application Im using firebase-js-sdk [1] together with firebaseui-web [2] to handle authentication.
After successful auth with any of the configured providers (e.g. password, google, apple, etc) I want to check which provider the user used. But immediately after successful authentication the user.providerData[] array that should contain the information is empty.
BUT if I reload my app the user.providerData[] array is suddenly populated correctly.
I´m checking for user data with something like this
import { getAuth } from "firebase/auth";
const auth = getAuth();
const user = auth.currentUser;
if (user) {
console.log(user.providerData)
}
After that the user object is fully populated (incl auth tokens, etc) but the user.providerData[] array is empty. Only after a page reload (CTRL-R) does the array get populated.
I searched both projects issues pages and documentation and didnt find anything that could explain this.
Im thankful for ANY idea where to look next!
EDIT
As suggested by #aside Im using onAuthStateChanged to check for updates of the user state.
onAuthStateChanged(
fbAuth,
(user) => {
if (user) {
console.log("onAuthStateChanged: user found");
console.log("onAuthStateChanged: user.providerData", user.providerData);
console.log("onAuthStateChanged: user", user);
} else {
console.log("onAuthStateChanged: no user found");
}
},
function (error) {
console.log("onAuthStateChanged:", error);
}
);
But even if I wait minutes after authentication is completed, still the user.providerData array is only populated after a page reload.
Here is a full demo: https://codesandbox.io/s/github/perelin/firebase-auth-providerdata-test
Thanks in advance :)
Im using
"firebase": "9.6.1",
"firebaseui": "6.0.0",
[1] https://github.com/firebase/firebase-js-sdk
[2] https://github.com/firebase/firebaseui-web
Your app should call getAuth().currentUser.reload() to refresh the local user data after login.
This could be done either in beforeRouteEnter() nav guard of the LoggedIn view:
// LoggedIn.vue
import { getAuth, signOut } from "firebase/auth";
export default {
async beforeRouteEnter(to, from, next) {
await getAuth().currentUser?.reload() 👈
next()
},
}
demo 1
Or in the onAuthStateChanged callback:
// main.js
onAuthStateChanged(
fbAuth,
async (user) => {
await user?.reload() 👈
},
)
demo 2
Your code is only running once instead of running every time the auth state is updated.
If you want to listen to any changes to the auth state, use a callback along with onAuthStateChanged as described here.
https://firebase.google.com/docs/auth/web/manage-users#get_the_currently_signed-in_user
import { getAuth, onAuthStateChanged } from "firebase/auth";
const auth = getAuth();
onAuthStateChanged(auth, (user) => {
if (user) {
// Check used provider here
const providerData = user.providerData;
// ...
} else {
// User is signed out
// ...
}
});
The reason checking/requesting the user object right after authentication does not work is that it might take firebase a second to update the providerData array. signInWithX might therefore return before the property is updated.

Get current users access token from Firebase in React Native

I am trying to get the Firebase authentication access token within a React Native application so that I can authenticate my API calls to a custom server. The Firebase documentation says I should get this token by using auth().currentUser.getIdToken(); however currentUser returns null.
I've tried to use getIdToken() in multiple areas of the application. I know the access token is generated as I can see it in the logs while using expo (user.stsTokenManager.accessToken).
Why is currentUser returning null and how can I get the accessToken?
You need to wrap user.getIdToken() inside of firebase.auth().onAuthStateChanged for user to be available. You can then use jwtToken in your header to authenticate your API calls. You need to import your Firebase configuration file for this to work.
let jwtToken = firebase.auth().onAuthStateChanged(function(user) {
if (user) {
user.getIdToken().then(function(idToken) { // <------ Check this line
alert(idToken); // It shows the Firebase token now
return idToken;
});
}
});
Just putting await before will work too just like this:
await auth().currentUser.getIdToken();
getIdToken returns a promise
firebase.auth()
.signInWithCredential(credential)
.then(async data => {
const jwtToken = await data.user?.getIdToken();
console.log(jwtToken);
})
Hook example
Unfortunately, its not reliable to directly get the token. You first have to listen to the authentication state change event which fires upon initialization since its asynchronous.
import {auth} from '../utils/firebase'
import {useState, useEffect} from 'react'
export default function useToken() {
const [token, setToken] = useState('')
useEffect(() => {
return auth().onAuthStateChanged(user => {
if (user) {
user.getIdToken(true)
.then(latestToken => setToken(latestToken))
.catch(err => console.log(err))
}
})
}, [])
return token
}
then use like so in your functional component
const token = useToken()
useEffect(() => {
if (token) {
// go wild
}
}, [token])

Using Firebase user UID with vuefire manual binding

In a simple SPA with Vue and Firebase, there are two routes: Login and Chat.
Upon login, the user is redirected to the Chat route where Firebase database bindings are done manually using vuefire's $bindAsArray(), inside the created() life-cycle hook. This is because the bindings require the uid assigned by the Firebase authentication to be available.
This works fine, until the user refreshes the page. If auth().currentUser is used to get the uid, it returns null. If the auth().onAuthStateChanged() watcher is used, Vue attempts to render the component before the Firebase database bindings are done. What am I missing?
I come across this scenario, as workaround I use component wrapper that has UID as property, if UID is null show a waiting message/animation else show your original component.
My real scenario is a little more complex to post it here (firebase, routing, vuex) but basically that wrapper component should look similar to this
<template>
<component :is="CurrentComponent" />
</template>
<script>
import App from './App';
import WaitingAnimation from './WaitingAnimation';
export default {
data() {
return {
Uid: null,
}
},
computed: {
CurrentComponent() {
return this.Uid == null ? WaitingAnimation : App;
}
}
beforeMount() {
//While Firebase is initializing `Firebase.auth().currentUser` will be null
let currentUser = Firebase.auth().currentUser;
//Check currentUser in case you previously initialize Firebase somewhere else
if (currentUser) {
//if currentUser is ready we just finish here
this.Uid = currentUser.uid;
} else {
// if currentUser isn't ready we need to listen for changes
// onAuthStateChanged takes a functions as callback and also return a function
// to stop listening for changes
let authListenerUnsuscribe = Firebase.auth().onAuthStateChanged(user => {
//onAuthStateChanged can pass null when logout
if (user) {
this.Uid = user.uid;
authListenerUnsuscribe(); //Stop listening for changes
}
});
}
}
}
</script>

How to get currently logged in auth state/user from angularfire2

I have an ionic2 app and am using Firebase and angularFire2. I'd like to get the current authentication state and current auth object/user from firebase using angularFire2.
Here's what's working so far - I can authenticate the user and subscribe to the FirebaseAuthState to get the facebook user object.
constructor(platform: Platform, private auth: FirebaseAuth) {
auth.subscribe((user: FirebaseAuthState) => {
if (user) {
// I could store user in localstorage, but I'd like to see an All Firebase solution
this.rootPage = TabsPage;
} else {
this.rootPage = LoginPage;
}
});
Now I can just set localstorage here and cache my user object to remember auth state. However, I am curious to see how I can use Firebase only without me implementing my own custom local storage key. I see that Firebase stores a localStorage key of it's own so knows that its logged in.
How can I get the auth object from code? Additionally, I tried the listed example in the AngularFire2 documentation to render the auth state in the template - but that gives me an error.
import {FirebaseAuth} from 'angularfire2';
#Component({
selector: 'auth-status',
template: `
<div *ng-if="auth | async">You are logged in</div>
<div *ng-if="!(auth | async)">Please log in</div>
`
})
class App {
constructor (#Inject(FirebaseAuth) public auth: FirebaseAuth) {}
}
Import: import { AngularFireAuth } from 'angularfire2/auth';
Inject: constructor(public afAuth: AngularFireAuth) { }
Check:
this.afAuth.authState.subscribe(res => {
if (res && res.uid) {
console.log('user is logged in');
} else {
console.log('user not logged in');
}
});
now in order to get the user info, you have to subscribe for getting the auth information. Ex
constructor(public af: AngularFire) {
this.af.auth.subscribe(auth => console.log(auth));// user info is inside auth object
}
auth object will be null if auth state does not exist
current authentication state is available from the injected FirebaseAuth. You can get the actual auth data auth.getAuth()
See: https://github.com/angular/angularfire2/blob/master/src/providers/auth.ts#L99
You can simply import AngularFireAuth and do this:
this.angularFireAuth.authState.subscribe(userResponse => {
if (userResponse) {
console.log('here is your user data');
localStorage.setItem('user', JSON.stringify(userResponse));
console.log(userResponse);
} else {
localStorage.setItem('user', null);
}
});
Here i am also using localStorage to save all data of my current user active on my app.

Resources