Firebase google auth does not sign out completely - javascript

Using the very clear simple examples provided by Google (Firebase Google Auth)I have been unable to log out from google.
Everytime sign I call this method using a button, it allows me to log in and navigates me to the local host.
function logGoogle() {
firebase.auth().signInWithPopup(provider).then(function(result) {
// This gives you a Google Access Token. You can use it to access the Google API.
var token = result.credential.accessToken;
// The signed-in user info.
var user = result.user;
location.href = 'http://localhost:8080';
// ...
}).catch(function(error) {
// Handle Errors here.
var errorCode = error.code;
var errorMessage = error.message;
// The email of the user's account used.
var email = error.email;
// The firebase.auth.AuthCredential type that was used.
var credential = error.credential;
// ...
console.log(errorCode);
console.log(errorMessage);
console.log(email);
console.log(credential);
});
}
however when i go back to the main menu which consists a log out button. It logs the session out, doesn't delete the session. When i log back in, i do not need to enter google creds. Bear in mind i am logged in to google chrome using an gmail account.
function logOutGoogle() {
firebase.auth().signOut().then(function () {
console.log("you logged off");
location.href = 'http://localhost/GoogleVue3/';
}).catch(function (error) {
alert(error);
});
}
I tried in incognito mode. entered google creds, went to the app, and decided to log out. Click on to sign in google, it automatically takes me to the app.
any advices?

You may not really want to sign out of Google in your browser (as it'll log you out of Gmail, and any other tabs/windows you're using Google apps). When you hit Firebase auth again, it jumps straight into the app (bypassing Google login because it was never really logged out of Google). Instead of logging in immediately, perhaps you want to see the Google account-picker. If so, here's the answer I gave to a related SO question.
Note that the issue you describe will only happen if you've only logged into a single Google/Gmail account, i.e., like you would in incog mode. If you've logged into >1, you'll always get the account-picker so Firebase can tell your app which user you've selected.

basically, firebase logout function logouts the application itself, but does not log out google on the browser.
To log out completely, you need the first sign out of the application then if successful, sign out of Google in the browser.
This then allows users not to log again when they've logged out.
function signoff() {
firebase.auth().signOut().then(function () {
window.alert("you have signed off successfully")
window.location = "https://mail.google.com/mail/u/0/?logout&hl=en";
// document.location.href = "https://www.google.com/accounts/Logout?continue=https://appengine.google.com/_ah/logout?continue=http://localhost/GoogleVue4";
}).catch(function (error) {
console.log(error);
})
}

Related

firebase twitter login error : auth/invalid-credential

I'm going to put a firebase-based Twitter login on a web page.
As shown in Docs, we created an app on the Twitter developer portal, put the app key and app secret in the firebase column, respectively, and added the firebase's callback URL to the Twitter app.
When you try to run by pressing the login button, a rare appears with the following error code.
auth/invalid-credential
The supplied auth credential is malformed or has expired.
Do you happen to know what I did wrong? Can I also know the solution?
JavaScript was used, and under the same conditions, Facebook and Google can log in well and retrieve user information.
Someone help me why Twitter is the only thing like this... I am desperate!
Below, I put my Twitter login code and other screenshots together in case I need it.
$(document).on('click', '#twiter', function () {
var provider = new firebase.auth.TwitterAuthProvider();
firebase.auth().useDeviceLanguage();
firebase
.auth()
.signInWithPopup(provider)
.then((res) => {
/** #type {firebase.auth.OAuthCredential} */
var token = result.credential.accessToken;
var user = result.user;
console.log(token)
console.log(user)
// ...
}).catch((error) => {
console.log(error)
console.log(error.code)
console.log(error.message)
});
});
enter image description here
enter image description here

Getting Uncaught TypeError in Firebase Auth get current user email

I am trying to get the email of the currently signed in user in my Firebase app, but it keeps giving me an error.
This is my code for getting the current user email:
user_email = firebase.auth().currentUser.email
The error that I get is:
Error Image
It looks like firebase.auth().currentUser is null at the time when your firebase.auth().currentUser.email runs. This is quite common, as Firebase refreshes the user's authentication state when the page loads, and this requires it to make an asynchronous call to the server.
For this reason, you should not assume there is a user signed in. You should either put a check around your current code:
if (firebase.auth().currentUser) {
user_email = firebase.auth().currentUser.email
}
Or (and often better) you should use a so-called auth state listener, to have your code automatically respond to changes in the user's authentication state. From the Firebase documentation on getting the currently signed-in user, that'd be:
firebase.auth().onAuthStateChanged((user) => {
if (user) {
// User is signed in, see docs for a list of available properties
// https://firebase.google.com/docs/reference/js/firebase.User
var uid = user.uid;
user_email = firebase.auth().currentUser.email;
// TODO: execute code that needs `user_email`
} else {
// User is signed out
// ...
}
});

Check if Firebase Facebook user exists without creating a user starting from anonymous user

In Firebase I need to check if a Facebook user exists without creating the user. Initially the user is anonymous, and they try to login with Facebook. I want this to fail if the Facebook account is not already linked to a user in my system. It won't be linked to the current user because they are anonymous,
If I use Auth.signInAndRetrieveDataWithCredential I expected a "auth/user-not-found" error, but instead the user is simply created. Is this a bug or expected?
let credential = firebase.auth.FacebookAuthProvider.credential(
event.authResponse.accessToken)
firebase.auth().signInAndRetrieveDataWithCredential(credential).then( (userCredential) => {
let user = userCredential.user
app.debug("DEBUG: Existing user signed in:"+user.uid)
this.loginSuccess(user)
}).catch( (err) => {
app.error("ERROR re-signing in:"+err.code)
$("#login_status_msg").text(err)
})
If I use User.reauthenticateAndRetrieveDataWithCredential instead I get the error "auth/user-mismatch" which makes sense because user is currently anonymous. However, I was expecting "auth/user-not-found" may be thrown instead if the credential doesn't exist, but that doesn't happen.
I don't see a way to take my anonymous user, have them login with Facebook and then see if another user is already linked to that Facebook credential without creating the user if it doesn't exist.
If you're wondering why? My scenario is:
The system allows anonymous users
A user logs in, then converts to a logged in user by registering with Facebook.
App uninstall
App reinstall
User starts up the app and is initially anonymous.
They try and login with Facebook again. At this point I want to stop them from creating a user if they don't have one already. If they have a user ID already, the code works fine and changes their anonymous account ID to the original user ID which is good.
I found a solution! It wasn't too hard to implement, but it does seem hacky.
So we know that when using signInAndRetrieveDataWithCredential(cred) for facebook login, the account is created even if it does not exist yet. To solve this, we need to make sure that we handle the following three things:
Detect if the account is new
Delete the current account that was created by firebase
Throw an error to get out of the current flow and return to wherever you were before.
I just implemented and tested this solution, and it seems to work great:
// ... do your stuff to do fb login, get credential, etc:
const userInfo = await firebase.auth().signInAndRetrieveDataWithCredential(credential)
// userInfo includes a property to check if the account is new:
const isNewUser = _.get(userInfo, 'additionalUserInfo.isNewUser', true)
// FIRST, delete the account we just made.
// SECOND, throw an error (or otherwise escape the current context.
if (isNewUser) {
firebase.auth().currentUser.delete()
throw new Error('Couldn\'t find an existing account.')
}
// If the user already exists, just handle normal login
return userInfo.user
The reason I did this was to ensure that users had to go through the "create account flow" in my app. Your case would be really easy to implement as well, something like the following:
let credential = firebase.auth.FacebookAuthProvider.credential(event.authResponse.accessToken)
firebase.auth().signInAndRetrieveDataWithCredential(credential)
.then(userCredential => {
const isNewUser = userCredential.additionalUserInfo.isNewUser
if (isNewUser) {
firebase.auth().currentUser.delete()
// The following error will be handled in your catch statement
throw new Error("Couldn't find an existing account.")
}
// Otherwise, handle login normally:
const user = userCredential.user
app.debug("DEBUG: Existing user signed in:"+user.uid)
this.loginSuccess(user)
}).catch( (err) => {
app.error("ERROR re-signing in:"+err.code)
$("#login_status_msg").text(err)
})
You can use linkAndRetrieveDataWithCredential:
let credential = firebase.auth.FacebookAuthProvider.credential(
event.authResponse.accessToken);
anonymousUser.linkAndRetrieveDataWithCredential(credential).then( (userCredential) => {
// Firebase Auth only allows linking a credential if it is not
// already linked to another account.
// Now the anonymous account is upgraded to a permanent Facebook account.
}).catch( (err) => {
// Check for code: auth/credential-already-in-use
// When this error is returned, it means the credential is already
// used by another account.
})
You can use the method fetchSignInMethodsForEmail to check if an specific email is already associated to an specific provider or not. Doing this you will be able to check if one if the SighInMethods of the email associated to your user contains Facebook.com or not.
I show you below an example about how I manage this cases on my application. I'm using an RxJavaWrapper on my code, but you will understand the point of how to manage it:
RxFirebaseAuth.fetchSignInMethodsForEmail(authInstance, email)
.flatMap { providerResult ->
if (!providerResult.signInMethods!!.contains(credential.provider)) {
return#flatMap Maybe.error<AuthResult>(ProviderNotLinkedException(credential.provider))
} else {
return#flatMap RxFirebaseAuth.signInWithCredential(authInstance, credential)
}
}
.subscribe({ authResult ->
//Manage success
}, { error ->
//Manage error
})
First I check the providers associated to the email of the user(You can retrieve it from the provider)
If the list of SignInMethods contains my credential provider, I throw an error, if not, I call my signInWithCredential method to create the user.
Continue your workflow.
What I did to solve this problem without relying on the call to linkAndRetrieveDataWithCredential to fail and using the catch block to sign in the already existing user is to save the userID field that getCurrentAccessToken returns.
const { userID } = data;
this.props.setFacebookId(userID); // saves the userID on the server
I can later check if this userID already exists next time the user signs up with facebook.

how to retrieve and handle Redirect errors using firebase Auth?

I'm developing mobile first app, using Firebase Auth. Firebase recommends redirect instead of popup. However, I can't seem to find any example of retrieving errors on using Oauth providers (facebook ,Google). Firebase has an example of handling error in SignwithPopup , but fore redirect it only states:
This error is handled in a similar way in the redirect mode, with the
difference that the pending credential has to be cached between page
redirects (for example, using session storage).
We show where to do error handling for redirect operation in the previous section of the same doc: Just search for "firebase.auth().getRedirectResult()" in this page specifically in the catch here:
firebase.auth().getRedirectResult().then(function(result) {
if (result.credential) {
// This gives you a Google Access Token. You can use it to access the Google API.
var token = result.credential.accessToken;
// ...
}
// The signed-in user info.
var user = result.user;
}).catch(function(error) {
// Handle Errors here.
var errorCode = error.code;
var errorMessage = error.message;
// The email of the user's account used.
var email = error.email;
// The firebase.auth.AuthCredential type that was used.
var credential = error.credential;
// ...
});
By the way, adding multiple auth providers and handling linking accounts perfectly is actually quite tricky because there are many sub-flows to take into account (e.g. what if the user wants to link but then signs-in an account where the emails do not match...). I recommend you use Firebase UI which provides a configurable UI component that will handle all these tricky flows for you.

How to manage google sign-in session (Google Sign-In JavaScript client)

im trying to implement google sign-in using their new API : https://developers.google.com/identity/sign-in/web/
Sign-in and Sign-out work fine.
My problem is that i dont know how to manage a session on other pages without a server side.
So i tried this code - https://developers.google.com/identity/sign-in/web/session-state
And it doesnt work well for me.
I dont want to have the google sign in button in every page. If i remove the "auth2.attachClickHandler.." part the whole code doesnt work.
All i want is to indicate in other pages (not in the page with the google button) if a user is still connected to or not.
Can you help me?
EDIT:
I tried the following code suggested in the answers but i get an error that says: " Uncaught TypeError: Cannot read property 'init' of undefined"
Code:
var auth2 = gapi.auth2.init({
client_id : 'ID.apps.googleusercontent.com'
});
auth2.then(function() {
var isSignedIn = auth2.isSignedIn.get();
var currentUser = auth2.currentUser.get();
if (isSignedIn) {
console.log("signed in");
// User is signed in.
// Pass currentUser to onSignIn callback.
} else {
console.log("NOT signed in");
// User is not signed in.
// call auth2.attachClickHandler
// or even better call gapi.signin2.render
}
});
You can load gapi.auth2 on all pages and call:
var auth2 = gapi.auth2.init(...);
auth2.then(function() {
var isSignedIn = auth2.isSignedIn.get();
var currentUser = auth2.currentUser.get();
if (isSignedIn) {
// User is signed in.
// Pass currentUser to onSignIn callback.
} else {
// User is not signed in.
// call auth2.attachClickHandler
// or even better call gapi.signin2.render
}
});
In this solution sign in button is displayed only when user is not signed in.

Categories