VueJS + Firebase Authentication Can't Access Session Before Scripts Load - javascript

So i'm working on a project and i'm struggling a bit...
I'm using VueJS for the frontend and Firebase Authentication to log users in.
I'm trying to determine whether a user is currently logged in or not using firebase.auth().currentUser;
(If returns null then no user is logged In) Sounds simple right!?
I'm running the currentUser() in my vueJS created() function. However, running firebase.auth().currentUser; here seems to always return null. But however, if i use a set timeout method then it is able to fetch the users data. It looks to me like vue is trying to fetch the data before it has loaded in.
I hope this isn't too hard to understand - i'm quite new to Vue and firebase!
Please find snippets of my code attached below.
Vue.config.devtools = true;
var app = new Vue({
el: '#app',
data: {
user: '',
loggedIn: false
},
created() {
var user = firebase.auth().currentUser;
if (user != null){
this.user = user;
this.loggedIn = true;
} else {
this.loggedIn = false;
}
}
})
Below are the firebase scripts i'm loading at the bottom of the page body
<script src="https://www.gstatic.com/firebasejs/7.14.1/firebase-app.js"></script>
<script src="https://www.gstatic.com/firebasejs/7.15.5/firebase-auth.js"></script>
<script src="https://www.gstatic.com/firebasejs/7.14.1/firebase-database.js"></script>
<script src="https://www.gstatic.com/firebasejs/7.14.1/firebase-analytics.js"></script>
<script src="js/firebaseConfig.js" type="text/javascript"></script>
Essentially, how can i fix this without using a setTimeout() method? and also how does firebase get this session, which script handles this?

firebase.auth().currentUser always returns null when the page is first loaded. It will only contain an actual user object after the SDK has determined that the user is actually signed in. There is no guarantee exactly how long that will take.
The preferred way to find out when that happens is to use an auth state observer, as shown in the documentation.
firebase.auth().onAuthStateChanged(function(user) {
if (user) {
// User is signed in.
// ...
} else {
// User is signed out.
// ...
}
});
You can use this callback to determine when it's time to render content for that individual user.
I suggest also reading more about the behavior of the Firebase Auth SDK in this blog.

async created() {
var user = await firebase.auth().currentUser;
if (user != null){
this.user = user;
this.loggedIn = true;
} else {
this.loggedIn = false;
}
}

Related

Firebase initialize app lose Current User

I have a web application using html-js-css and a flask server.
My web app is a multi-pages app which apparently means that I have to Initialize firebase for each page in which i want to use it -.-
The problem is that every time I initialize firebase app, I lose the current user so while in my main page, after log-in, if I write:
const USER = firebase.auth().currentUser;
console.log(USER.uid);
I get my user ID, as soon as I move to another page and repeat the above code, I get the error:
TypeError: USER is null
Is there a way to either:
avoid Initializing the firebase-app at avery page
keep the CurrentUser (even storing it securely somewhere)
Thank you
Workaround:
I got this workaround working before Frank answer which is probably the best way to proceed. Instead I just stored the user id in an encrypted variable accessible to all pages.
Since the main.html page is always loaded, I store/removed the variable in a onAuthStateChanged listener there so as soon as the user is logged out, that variable is removed:
firebase.auth().onAuthStateChanged(function(user) {
if (user) {
cached_uid = JSON.stringify(user.uid);
cached_uid = btoa(cached_uid);
localStorage.setItem('_uid',cached_uid);
} else {
localStorage.removeItem('_uid');
}
});
then on the other pages:
function loadUID(){
var uid = localStorage.getItem('_uid');
if (!uid) return false;
uid = atob(uid);
uid = JSON.parse(uid);
return uid
}
I followed this to find this solution:
How to send variables from one file to another in Javascript?
You will need to initialize the Firebase app on each page, but that is supposed to be a fairly cheap operation.
To pick up the user on the new page, Firebase runs a check against the server to ensure the user token is still valid. Since this code calls a server, its result likely isn't available yet when your firebase.auth().currentUser runs.
To solve this, run the code that requires a user in a so-called auth state change listener:
firebase.auth().onAuthStateChanged(function(user) {
if (user) {
// User is signed in.
} else {
// No user is signed in.
}
});
Also see the Firebase documentation on getting the currently signed in user.

Firebase - SPA web application - issue with logout

I've recently made simple SPA application which connects to firebase using Google provider and loads data for authenticated user.
Everything was great, until I tried to sign-out user using following method from documentation:
firebase.auth().signOut()
Logout was succesful, but after this, I can't sign-in again, because I'm receiving following error:
updateCurrentUser failed: First argument "user" must be an instance of Firebase User or null.
When I checked network tab in my browser, I've seen my user data in responses, so there Was an issue propably with the firebasewebui.
Things which I also tried
Sign-in in another browser - working
Sign-in in incognito mode - not working
Sign-in from other domain (for instance fake domain authorized in firebase console) - working
Wiped my entire Google Chrome profile from computer and add it again - not working
Sign-in from Android application - working (here there is no issue with sign-out and sign-in)
So it looks like it is something connected with domain and browser combination.
Here is my js code:
const firebase = require('firebase/app');
require('firebase/auth');
require('firebaseui');
const initializeFirebase = () => {
const config = { /* config */ };
firebase.initializeApp(config);
firebase.auth().onAuthStateChanged(function (user) {
if (user) {
// loads data
} else {
// visibility staff
initializeFirebaseAuthForm();
}
});
}
const initializeFirebaseAuthForm = () => {
const uiConfig = {
callbacks: {
signInSuccessWithAuthResult: function (authResult, redirectUrl) {
return false;
},
uiShown: function () {
visibilityManager(false);
}
},
signInFlow: 'popup',
signInOptions: [
firebase.auth.GoogleAuthProvider.PROVIDER_ID
]
};
let ui = null;
if (firebaseui.auth.AuthUI.getInstance()) {
ui = firebaseui.auth.AuthUI.getInstance();
} else {
ui = new firebaseui.auth.AuthUI(firebase.auth());
}
ui.start('#firebaseui-auth-container', uiConfig);
}
document.addEventListener('DOMContentLoaded', function () {
initializeFirebase();
});
In such case, my observer registered in onAuthStateChanged is not fired.
I've found answer by myself.
There was couple of issues. First of all, Firebase initialization should be placed as 'global' like for example here: https://github.com/firebase/firebaseui-web/, especially this lines:
firebase.initializeApp(config);
ui = new firebaseui.auth.AuthUI(firebase.auth());
Secondly, with my code from input, I've to get existing instance of ui using conditional. In firebase github, ui was created always using new operator and it was always created once per script run.
I found out, that there is workaround - ui instance can be deleted using delete() promise.

Firebase - keep user signed in while localStorage object is valid

I have an app I'm building with Ionic, Angular2, and Firebase.
What I'm currently doing is that when a user log's in or registers, their auth.currentUser information is being saved in localStorage. My code is currently assuming that if a user has the user variable in localStorage set that the user is also signed in. However, I just realized that that isn't actually the case.
My localStorage variable user looks like this:
and I'm getting it like this:
ngOnInit() {
Promise.all([ //data storage get all..
this.storage.get('user')
])
.then(([user]) => {
this.userData = user; //set the user storage to this.userData
console.log(this.userData)
})
.catch(error => {
console.log("Storage Error.");
});
}
So I have all of the users information, except the fact that they aren't actually signed in... So when I do:
this.afAuth.auth.onAuthStateChanged((user) => {
if (user) {
console.log(user)
} else {
console.log("Not logged in")
}
});
It shows the user isn't logged in. Is it possible for me to keep the user logged in while I have the localStorage information?
Or maybe just have the login state always be logged in unless the user signs out? With it never expiring?
What should I do at this point? Any advice would be great! Thank you.
Firebase manger user in a different way. You should not depend on localstorage to detect if user is logged it. You should depend on firebase to check if user is logged in. Since firebase is built on web sockets, it should be really quick. So let rewrite the ngOnInit as follows:
ngOnInit() {
const user = this.afAuth.auth.currentUser;
if (user) {
this.userData = user;
} else {
// force them to reauthenticate
user.reauthenticateWithCredential(credential)
.then(function() {
// User re-authenticated.
this.userData = this.afAuth.auth.currentUser;
}).catch(function(error) {
// An error happened.
});
}
}
Read more about managing users in Firebase here: https://firebase.google.com/docs/auth/web/manage-users. Hope this helps.

Firebase Restrict Access to other pages without user logged in

I have an index.html page that will redirect to home.html after the correct login. I have solved the login and logout part. my problem is I can access home.html directly on the URL without logging in.
here is some snippet of my home.html
<script>
var config = {
apiKey: "xxxxxx",
authDomain: "firebaseapp.com",
databaseURL: "firebaseio.com",
};
firebase.initializeApp(config);
const auth=firebase.auth();
const db=firebase.database();
var user = firebase.auth().currentUser;
if (user) {
//blank if correct login
} else {
window.location.href = 'firebaseapp.com/index.html';
}
</script>
I put this on the beginning of my home.html so that if the page will be accessed directly it will return to the index. It worked on redirecting to the index.html BUT even when i login correctly, it still redirects me to the index.html
It seems like the firebase gets the auth too fast that it cannot initialize the currentUser values properly thus giving a null result. Any suggestion on how to restrict direct access using the URL would really help.
Thanks!
try using firebase.auth().onAuthStateChanged instead of firebase.auth().currentUser; it is the recommended way to get the current user.
Getting the user by currentUser may cause a problem similar to what you are seeing. This is from the official doc of firebase.
Note: currentUser might also be null because the auth object has not finished initializing. If you use an observer to keep track of the user's sign-in status, you don't need to handle this case.
Try to get the current user like this:
firebase.auth().onAuthStateChanged(function(user) {
if (user) {
// User is signed in.
} else {
// No user is signed in.
}
});
I'm not that experienced jet, but this has worked for me, but I'm not sure if it is the best way. I simply gave my body an id and added this JavaScript code:
var auth = firebase.auth();
auth.onAuthStateChanged(function(user) {
if (user) {
document.getElementById('homeBody').style.visibility = "visible";
} else {
document.getElementById('homeBody').style.visibility = "hidden";
}
});
I think this will do it for the starting companies. As your business grows, I recommend that you consider taking more security

Google Firebase - Polymerfire, getting a callback on the initial application initialization

Is there anyway to do something like this with firebase.
var loaded = false;
var app = firebase.initializeApp(config);
app.then(function(user) {
// initialization complete
loaded = true;
if(user){
// user logged in
}
else
{
// user not logged in
}
});
The above solution, if possible, would provide me with the knowledge that a user has or has not been logged in, as well as the information the application is attempting to get a user.
I can then only show the page to the user once I know that the page is not going to change in the next second.

Categories