FirebaseUI-web: no recognised user after account login - firebase

The Firebase authListener shows the account chooser but doesn't recognise any user the first time I try to login.
Then, trying to login again for a second time, FirebaseUI skips the account chooser and immediately redirects back, after which the Firebase authListener does recognise the user. The same is true for the Google account chooser as for "Sign in with email" and choosing the same Google address.
This problem makes all my users need to press the login button twice. Once for the account chooser and a second time to actually login with the user now recognised.
Here is my build:
Firebase initialisation
firebase.initializeApp(config.firebase)
firebase.auth().onAuthStateChanged(user => {
if (user) {
return console.log('found this user! ', user)
}
console.log('no user found during authListener!')
})
firebase.auth().getRedirectResult()
.then(result => { console.log(result.user) })
.catch(error => { console.log(error) })
Here is what happens when the login page is mounted
let ui = firebaseui.auth.AuthUI.getInstance()
if (!ui) {
ui = new firebaseui.auth.AuthUI(firebase.auth())
}
ui.start('#firebaseui-auth-container', uiConfig)
Here is my config:
uiConfig = {
signInSuccessUrl: '/',
signInOptions: [
{
provider: firebase.auth.EmailAuthProvider.PROVIDER_ID,
requireDisplayName: false
},
firebase.auth.GoogleAuthProvider.PROVIDER_ID,
],
tosUrl: 'localhost'
}
Versions:
"firebase": "^5.0.4",
"firebaseui": "^3.0.0",
PS:
My website is an SPA

I "solved" this problem by adding the following to the config object:
credentialHelper: firebaseui.auth.CredentialHelper.NONE
This turns off the account chooser entirely, instead prompting users to type in their email address, resulting in a much nicer user experience IMHO compared to the ugly and confusing account chooser.

Related

How to use SSR Firebase Authentication in Nuxt-js with Middleware?

In my project , user can login in system . If users do not choose "Remember me " option in beginning, their session will end after page closed entirely.
My firebase works Client Side
in firebase.js
export default ({ store, $storage }) => {
onAuthStateChanged(auth, async user => {
if (user && !user.isAnonymous) {
store.commit('firebase-auth/setUser', user);
if (user.emailVerified) {
$storage.setCookie('firebase_token', user.accessToken);
}
} else {
enableGoogleOneTapSignIn(user);
}
});
};
in MiddleWare auth.js
export default ({ $storage, req, redirect }) => {
if (process.server) {
const token = !!req.headers.cookie.firebase_token;
if (!token) return redirect('/');
} else if (process.client) {
const token = !!$storage.getCookie('firebase_token');
if (!token) return redirect('/');
}
};
This code controls if user signed in or not . This works in server and client side.
The problem is ; When user chose "remember me" option at the beginning , session will not finish even if user closes entire browser. And if user opens the browser again , his session will continue and he will be logged-in already but in this scenario I can not reach cookie because it was deleted when browser was closed .
If user comes with a direct link like abc.com/user/my-profile when browser was closed, user will not reach his profile beacuse cookie was cleaned . I need to find a good way for this problem .

User redirect and authentication with middleware of Nuxt

I'm trying to redirect a user to a login page if the user is not logged in when he tries to access certain pages with the following code.
// middlware/authenticated.js
import firebase from 'firebase'
export default function ({ store, redirect }) {
let user = firebase.auth().currentUser
store.state.user = user //this doesn't work
if (!user) {
console.log('redirect')
return redirect('/login')
}
}
However, the problem is with this code when I refresh a page I'm redirected to login page although without using the middleware, I can stay in the same page with logged in. For some reasons, which I don't know why, firebase can't work in middleware.
How should I modify this middleware or implement this function?
Thanks.
//middleware/authenticated.js
export default function ({
store,
redirect
}) {
if (!store.getters['index/isAuthenticated']) {
return redirect('/login')
}
}
//post.vue
async mounted () {
if (process.browser) {
let user;
if (!this.user) user = await auth(); // this auth is a plugin
await Promise.all([
this.user ? Promise.resolve() : this.$store.dispatch("setUser", { user: user || null })
]);
this.isLoaded = true;
}
},
//plugins/auth.js
import firebase from '~/plugins/firebase'
function auth () {
return new Promise((resolve, reject) => {
firebase.auth().onAuthStateChanged((user) => {
resolve(user || false)
})
})
}
export default auth
By default Firebase persists the users logged in status on successful authentication. This example uses the session, to store the user uid and cookies to store the users token and used in situations where the sessions has ended (example when browser is closed) and then a new session started but where the user is still authenticated according to Firebase. In cases like these the user will not need to sign in to view protected resources.
Your basic Middleware to protect it should look like this (if you have a Store Module called User)
export default function ({ store, redirect }) {
if (!store.getters['modules/user/isAuthenticated']) {
return redirect('/auth/signin')
}
}
In your main Store you use the ServerInit Function to get the User if there is one saved in the Cookies and load it into your User Store Module which will be used for verification in the Middleware.
Your User Store Module should look like this, and keep in mind that you remove the Cookie when you Log the User out so that he is fully logged out.
I used the things i mentioned above as the beginning of my Authentication and modified it a bit, which you can also do. Most of the credit goes to davidroyer who has set up this nice Github Repo which includes all needed files as a good example on how to accomplish your goal.

Unusual redirects

I create an application with Vue.js, vue-router and firebase. In the main.js file I put this code:
created() {
firebase.initializeApp({
apiKey: "xxxxxxxxxxx",
authDomain: "xxxxxxx.firebaseapp.com",
databaseURL: "https://xxxxxxxxxx.firebaseio.com",
projectId: "xxxxxxxxxx",
storageBucket: "",
})
firebase.auth().onAuthStateChanged((user) => {
if(user) {
this.$store.dispatch('autoSignIn', user)
}
})
}
This is a Vue-Store:
state: {
user: null
},
mutations: {
setUser(state, payload) {
state.user = payload
}
},
actions: {
autoSignIn({commit}, payload) {
commit('setUser', {
id: payload.uid
})
}
}
In the vue-router, I made sure that before proceeding to the root directory, it checked whether the user was authorized. If not, redirect it to the login page. And in the login page, it checks whether the user is authorized. If not then redirects to the root directory. So, I'm logged in and I'm in the root directory. I reload the page and I immediately redirect to the login page and immediately redirected to the root directory and nothing else happens. All this happens in 1 second, and looks ugly.
firebase.auth().onAuthStateChanged() is asynchronous. So by the time we are able to access the user the route guard is being executed . That's the reason you are being redirected to the login page.
By that time the async call has finished we have access to the user. Since you are checking for user in the login page and now that the user is available you are kicked back to root route.
Firebase by default stores a token in localStorage under the key 'firebase:authUser' for keeping the auth state persisted .
So you can check whether this key is present in localStorage in your route guard
router.beforeEach((to, from, next) => {
//check local storage
let loccalStorageKeys = Object.keys(window.localStorage);
const firebaseAuthUser = loccalStorageKeys.filter(item => item.startsWith('firebase:authUser'))[0];
if(firebaseAuthUser){
next();
}else{{
next('/login');
}}
})
Since the check is synchronous , it should prevent the jumping redirects.
Or the alternative would be to persist the vuex state corresponding to the user using a vuex plugin called vuex-persistedstate. Then check for the user state for guarding the routes. Then when the user logs out clear the user state. Check out this post regarding vuex-persisted state.
NOTE:
As of firebase v4.12.0 the auth state persistance(for LOCAL persistance) is moved from local storage to indexedDB.
As this is an internal implementation of firebase and may change in future, so relying on checking whether firebase:authUser is present in local storage to confirm user's login status is not a good idea.
So it would be better to persist the user data as mentioned in the alternative method above and use that to check the user is logged in or not

Not able to maintain user authentication session firebase

I am using email & password authentication to logging in user, from my firebase dashboard i have set session expiration time to 2 months . However when i am closing my app from background and then after reopening of app i am getting var user = ref.getAuth(); as null
Does firebase does't take care of this? How to keep user logged in for a long period of time?
Below is the piece of code i am using to login user. I am using react-native
ref.authWithPassword({
email : 'username',
password : 'password'
}, function(error, authData) {
if (error) {
console.log("Login Failed!", error);
} else {
navigatorReference.push({name:'myFeed'})
console.log("Authenticated successfully with payload:", authData);
}
});
Firebase should take care of this. Double check your configuration in the Login & Auth tab in your App Dashboard to make sure you have that setup properly.
You could also try passing along the configuration like so...
ref.authWithPassword({
email : 'username',
password : 'password'
}, function(error, authData) { /* Your Code */ }, {
remember: "default"
});

Not receiving email in user object when authenticating with facebook

I'm using angularfire to authenticate users via facebook. I get the user object, which contains a property called thirdPartyUserData. The basic information is in here, but email is not.
I have included email in the scope
$scope.facebookLogin = function() {
login.$login('facebook', { rememberMe: true, scope: 'email' })
.then(function(user) {
console.log(user);
}
});
.factory('login', function ($firebaseSimpleLogin) {
var ref = new Firebase("https://housemates.firebaseio.com/");
return $firebaseSimpleLogin(ref);
});
When the login pops up, it asks me if I am happy to give my email, so I know that part is working, but nothing email related shows anywhere in the user object.
Object {uid: "facebook:NUMBERS", provider: "facebook", id: "NUMBERS", displayName: "Jim Jansonby", thirdPartyUserData: Object…}accessToken: "TOKEN"displayName: "Jim Jansonby"firebaseAuthToken: "TOKEN"id: "NUMBERS"provider: "facebook"thirdPartyUserData: Objectage_range: Objectmin: 21__proto__: Objectfirst_name: "Jim"gender: "female"id: "NUMBERS"last_name: "Jansonby"link: "https://www.facebook.com/app_scoped_user_id/NUMBERS/"locale: "en_GB"name: "Jim Jansonby"picture: Objecttimezone: 1__proto__: Objectuid: "facebook:NUMBERS"__proto__: Object
Versions
Chrome 37.0.2062.124 / OSX 10.10
Firebase ~1.1.0
Angularfire ~0.8.2
SimpleLogin ~1.6.4
Not using ionic or cordova, just running on desktop

Resources