Google sign in API does not work on Mozilla Firefox - javascript

I am currently handling a web app that requires the user to sign in using their google account to gain access to the core functionalities. When using Google Chrome everything works the way it's expected to work: The user clicks "Sign In", a pop-up opens with Google sign in form, the user signs in, and he will be transferred to the main page. (good)
HOWEVER
When using Mozilla Firefox 38.0.1, the web app cannot be used in any way because when the user clicks "Sign In", it does nothing. Literally nothing, not even an error on the console.
Here is the login button:
//head
<meta name="google-signin-client_id" content="{CLIENT ID}.apps.googleusercontent.com">
//body
<button class="g-signin2 login-button" data-onsuccess="onSignIn"></button>
Is there a currently known issue with Firefox and Google Sign In API?

Ok, found the solution: I followed this. Basically, I didnt use the easy integration of the Google SignIn and I just created a custom handler and listeners. I kept the original buttons because it is required and just added this javascript:
HTML
<script src="https://apis.google.com/js/plus.js?onload=appStart"></script>
JS
//googleSignIn.js
var auth2; // The Sign-In object.
var googleUser; // The current user.
/**
* Calls startAuth after Sign in V2 finishes setting up.
*/
var appStart = function() {
console.log('appStart()')
gapi.load('auth2', initSigninV2);
};
/**
* Initializes Signin v2 and sets up listeners.
*/
var initSigninV2 = function() {
auth2 = gapi.auth2.getAuthInstance({
client_id: '{CLIENT ID}.apps.googleusercontent.com',
scope: 'profile'
});
// Listen for sign-in state changes.
auth2.isSignedIn.listen(signinChanged);
// Listen for changes to current user.
auth2.currentUser.listen(userChanged);
// Sign in the user if they are currently signed in.
if (auth2.isSignedIn.get() == true) {
auth2.signIn();
}
};
/**
* Listener method for sign-out live value.
*
* #param {boolean} val the updated signed out state.
*/
var signinChanged = function (val) {
console.log('Signin state changed to ', val);
};
/**
* Listener method for when the user changes.
*
* #param {GoogleUser} user the updated user.
*/
var userChanged = function (user) {
console.log('User now: ', user);
googleUser = user;
};
$('.login-button').on('click', function() {
console.log('signing in')
auth2.signIn().then(function(user) {
//callback to handle sign in
onSignIn(user);
});
})
I'm not sure what caused the issue of the Google Sign In to not work on mozilla. If anyone knows this to be a known issue please let me know in the comments.
Bottomline: easy integration of Google Sign In did not work on Mozilla. Had to integrate using listeners.

Related

Google Identity Service Oauth2 detect if consent pop-up is closed

👋 I am using Google Identity Services, and facing some problems. Have a look at the function below to loginUser and get the access_token:
const client = (window as any).google.accounts.oauth2.initTokenClient({
client_id: process.env.GOOGLE_CLIENT_ID,
scope: `profile email`,
callback: '' // defined at request time
});
const loginUser = async () => {
const tokenResponse = await new Promise<TokenResponse>((resolve, reject) => {
try {
// Settle this promise in the response callback for requestAccessToken()
client.callback = (resp) => {
if (resp.error !== undefined) {
reject(resp);
}
resolve(resp);
};
// requesting access token
client.requestAccessToken({ prompt: 'consent' });
} catch (err) {
console.log(err)
}
});
return tokenResponse;
}
Invoking loginUser() causes a new pop-up.
If the user selects an account, I get the tokenResponse (which contains access_token). Works great. 🚀
But if the user closes the pop-up, the Promise never resolves, since we are waiting for the callback to fire, which never happens. 😥
Is there a way we could detect if the user has closed the pop-up?
I think you can do something in the "error_callback". You can find details at: Handle Errors
const client = google.accounts.oauth2.initCodeClient({
client_id: 'YOUR_GOOGLE_CLIENT_ID',
scope: 'https://www.googleapis.com/auth/calendar.readonly',
ux_mode: 'popup',
callback: myCallback,
error_callback: myErrorCallback // You can do something when popup window closed
});
(Update) Prospective Solution
It looks like the google developers have added the error handlers now into the new Google Identity Services. :)
Checkout the documentation at https://developers.google.com/identity/oauth2/web/guides/error.
(I still haven't tested it. Hence putting it as a prospective solution). Happy coding!
Original Answer
Here are the two solutions which you can consider if you're facing this issue.
Solution 1
Go back to the old gapi based login. (Not recommended, as it will be deprecated soon). For more details, on deprecation, refer to this blog by Google.
Solution 2
We add a javascript focus event listener just after opening the popup. So, whenever the user closes the popup and returns to the parent window, we shall consider it as client_focused_back_to_window / pop_up_closed event.
The only edge case is when the user doesn't close the popup and directly returns to the window; the focus event listener will be fired. But I think that's okay because if the user again clicks on Sign In with Google button again, the same pop-up window gets reused (thanks to _blank parameter used by Google Identity services while creating the popUp window).
const client = (window as any).google.accounts.oauth2.initTokenClient({
client_id: process.env.GOOGLE_CLIENT_ID,
scope: `profile email`,
callback: '' // defined at request time
});
/**
* Function to login the user and return the tokenResponse
*
* It throws error if the login fails or the user cancels the login process
*/
const loginUser = async () => {
const tokenResponse = await new Promise<google.accounts.oauth2.TokenResponse>(
(resolve, reject) => {
const focusEventHandler = () => {
reject({
error: 'client_focused_back_to_window',
});
window.removeEventListener('focus', focusEventHandler); // removing the event listener to avoid memory leaks
};
// adding an event listener to detect if user is back to the webpage
// if the user "focus" back to window then we shall close the current auth session
window.addEventListener('focus', focusEventHandler);
// Settle this promise in the response callback for requestAccessToken()
client.callback = (resp) => {
if (resp.error) {
reject(resp);
}
resolve(resp);
};
// requesting access token
client.requestAccessToken({ prompt: 'consent' });
},
);
return tokenResponse;
}
PS: We've been using this solution in production, and so far, thousands, if not millions, of users have tried to log in via Google. Everything is working fine so far. 🙂
It appears that this is not working for the current version of GSI.
It did work for the old gapi version and if the popup were to be closed you would get a response with the error: {error: "popup_closed_by_user"}. As referenced in this answer: Google SSO login error: "popup_closed_by_user"
Hopefully adding the #google-oauth tag will allow someone at Google to see this and hopefully update this script.
Please see other referenced question: Google Oauth popup cancellation callback
This is referring to the documentation on https://developers.google.com/identity/oauth2/web/guides/use-code-model#trigger_oauth_20_code_flow and https://developers.google.com/identity/oauth2/web/guides/use-token-model#initialize_a_token_client
In fact the documentation states: Users may close the account chooser or sign-in windows, in which case your callback function will not be invoked..
Question for Google - how can we detect this?!

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.

How to detect login window close event on LinkedIn Javascript SDK?

I am using LinkedIn Javascript SDK to log my users in, and I need to detect if a user closes the login/auth window before they complete the login or authorization. Current SDK doesn't fire the login callback when the window is closed (I naturally expect it to be called with IN.User.isAuthorized() set to false just like in Facebook Javascript SDK).
How can I detect when the user closes the Login with LinkedIn window?
The LinkedIn API is a bit of a nightmare to deal with.
I had a similar issue where it was firing multiple requests if they opened the auth window more than once. I solved this by adding a count each time they opened the window and then ignoring everything if count > 1. My solution involves Angular and Promises so I'm not going to post the full solution.
For you, I would just add authTriggered and authComplete variables. The triggered gets set when they click they link/button to authorise with LinkedIn and the complete variable gets set in the auth callback.
Something like this perhaps?
var LinkedIn = LinkedIn || {};
LinkedIn = {
authTriggered: false,
authComplete: false,
authorise: function() {
IN.User.authorize(function() {
this.authComplete = true;
});
}
};
var authLink = document.getElementById('auth-link');
authLink.addEventListener('click', function(e) {
e.preventDefault();
LinkedIn.authTriggered = true;
LinkedIn.authorise();
});
Instead of IN.User.authorize() please use IN.UI.Authorize() as
var linkedin = IN.UI.Authorize().place();
linkedin.onWindowRemove.subscribe(function() {
// perform some action
});
thanks sanju for this answer
https://sanjutalks.wordpress.com/2017/10/04/linkedin-javascript-sdk-detecting-login-windows-close-event/

Checking for signed in Google user with Google Sign-in

I'm working with the Google Sign-in library.
If I use Google's provided sign in button on my page, it quickly changes states to show that I am logged in before I've taken any action.
Is it possible to detect this signed in state without using Google's default button?
The main issue is that their button doesn't allow for checking for the hosted domain of the logged in account.
I was trying to use the GoogleAuth.currentUser.get() function to get the user, but as the documentation notes:
in a newly-initialized GoogleAuth instance, the current user has not been set. Use the currentUser.listen() method or the GoogleAuth.then() to get an initialized GoogleAuth instance.
Using GoogleAuth.then(onInit, onFailure) as mentioned above correctly retrieves the logged in state of the user.
/**
* The Sign-In client object.
*/
var auth2;
/**
* Initializes the Sign-In client.
*/
var initClient = function() {
gapi.load('auth2', function(){
/**
* Retrieve the singleton for the GoogleAuth library and set up the
* client.
*/
auth2 = gapi.auth2.init({
client_id: CLIENT_ID,
scope: 'profile'
});
// Called once auth2 has finished initializing
auth2.then(checkForLoggedInUser, onFailure);
});
};
function checkForLoggedInUser() {
var user = auth2.currentUser.get();
var profile = user.getBasicProfile();
console.log('Email: ' + profile.getEmail());
}
You can use the GoogleAuth.isSignedIn.get() method:
// 1. Make gapi.auth2 available (using gapi.load("auth2", ...))
// 2. Initialize the library (using gapi.init({ ... }))
const isSignedIn = gapi.auth2.getAuthInstance().isSignedIn.get();
isSignedIn is true if the user is signed to Google, otherwise false.

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