Hi I was trying to use this library for authentication and I'm able to display the login pop-up but after logging in it doesn't call any of the Promise .thens or the isSignedIn and currentUser listeners.
window.gapi.auth2.init({
client_id: googleClientId,
scope,
}).then(() => {
console.log('signed in', window.gapi.auth2.getAuthInstance().isSignedIn.get());
window.gapi.auth2.getAuthInstance().isSignedIn.listen((signedIn) => {
console.log(signedIn);
});
window.gapi.auth2.getAuthInstance().currentUser.listen((user) => {
console.log(user);
});
});
(some time later)
window.gapi.auth2.getAuthInstance().signIn().then((...args) => console.log(args), (...args) => console.log(args));
I'm just going to go back to writing my own with the REST interface, but was curious as to what's going on.
Having the exact same issue. Thought I was going nuts. tried everything. Thanks for reporting.
@fozzle did you find any work around?
I'm having the same issue gapi.auth2.getAuthInstance().signIn() should return a promise, yet it doesn't..
@afterburn it does return a promise for me. But the listener still does not work properly
I'm running into the same problem, anyone have any idea what might be causing this?
Edit:
I was running my localserver on port 3000 but had only whitelisted port 8080 in my Google dev console.
Apparently gapi.auth2.getAuthInstance().signIn() needs to be triggered by user-interaction (e.g. click event) to work - at least that was prohibiting it from doing _anything_ in the API implementation I'm working on at the moment.
I'm having the same problem.
Not working in latest iOS or in Android 5.02 or higher.
It's working in Android 4.
Anyone experiencing the error, could you mention:
Thanks!
I'm having this exact problem. Calling gapi.auth2.getAuthInstance().signIn(), the account chooser pops up but when I select an account, the dialog closes and the then() callback is never called. Subsequent queries for login status indicate I am not logged in.
The first time through I had to approve the app. Everything seems like it's working except that I'm not getting logged in and the callback isn't called.
There are no errors of any kind being displayed on the console. Chrome 55, no special modes or plugins.
The mysterious part is that this problem manifests in an Aurelia app. The exact same javascript code in a vanilla web page (in a
OK, solved my problem. The issue is that by default Aurelia replaces the whole <body> with the app. When this happens, it stomps on the hidden iframe that gapi requires to communicate with Google. Solution is to create a div element inside body and attach the aurelia app to that.
Hope this helps someone else.
I was having the same issue and ended up doing the following:
Promise.resolve(window.gapi.auth2.getAuthInstance().signIn())
.then(() => { ... })
This is probably not ideal, but it worked for me.
@fozzle could you provide a minimal snippet that reproduces the issue? It works for me.
I'm having the same problem
Here's a pug template that you can easily render with the simplest express app:
doctype html
html(lang='en')
head
title test
meta(charset='utf-8')
meta(name='viewport', content='width=device-width, initial-scale=1')
script(src='https://apis.google.com/js/api.js?onload=start', async, defer)
script.
function start() {
gapi.load('client:auth2', initClient)
}
function initClient () {
auth2 = gapi.auth2.init({
client_id: 'YOUR_CLIENT_ID.apps.googleusercontent.com',
scope: 'openid https://www.googleapis.com/auth/drive.install https://www.googleapis.com/auth/drive.metadata.readonly https://www.googleapis.com/auth/activity'
})
}
function handleSignInClick () {
auth2.signIn({ prompt: 'none' }).then(immediateSignInCallback, immediateSignInError)
}
function immediateSignInCallback (arg) {
// THIS IS NEVER CALLED
console.log('immediate sign in worked')
console.log(arg)
}
function immediateSignInError (err) {
// THIS IS NEVER CALLED
console.log('immediate sign in errored')
console.log(err)
}
body
button#signin-button(onclick='handleSignInClick()') Sign in with Google
Hi @czzarr, thanks for the snippet. I was indeed able to reproduce the issue with it.
The parameter prompt: 'none' seems to have unveiled an edge case that make the promise never resolve. We will investigate this bug.
However, this parameter is not meant to be used when using Google Sign-In JS library. By passing prompt: 'none' as parameter, you require the Authorization endpoint not to display any account chooser or consent flow (see doc). This means that the Authorization endpoint will try to automatically select an user - however, this will fail in many very common scenarios:
The library takes care of loading any already signed in user upon initialization. You should rely on that to automatically sign in users on page load.
Does that make sense? Let me know if you have any other question.
Hi @TMSCH,
Thank you for your quick answer. I'm not sure I understand clearly when prompt: 'none' should be used then?
More importantly, how do you sign in someone who has already authorized the app with the correct scopes without prompting for consent? (what used to be immediate: true)
What I want to do is the following: try to sign in someone transparently, and if that doesn't work (because the app isn't authorized yet, or not with the correct scopes), start a back-end server flow (so that I can store a refresh_token).
@czzarr when using gapi.auth2, the library will take care of automatically signing in the user if they were previously signed in to the app in an earlier session. This is similar to the immediate: true mode of gapi.auth. Which is why prompt: 'none' is not meant to be passed as a parameter when this library is used.
Are you using the refresh_token in the backend to perform server to server API calls?
@TMSCH When you say gapi.auth2 will take care of automatically signing in the user, are you talking about using the GoogleAuth.signIn() method without any parameter?
I still need to store the refresh_token on the back-end because I use it to renew channels to the Drive Push API. I use GoogleAuth.grantOfflineAccess() to launch a back-end auth flow.
Also when exactly should one use GoogleUser.reloadAuthResponse()?
EDIT: I just tried plain signIn() and indeed the method does work as you say, but I don't understand how I can launch a back-end flow to get a refresh_token on the server in the case that the user hadn't authorized the app before since it handles everything automatically and never gives you an error case.
@czzarr gapi.auth2.init({...}) will take care of automatically sign in the user, but a previous call to gapi.auth2.signIn is necessary for this to happen. In other words, once the user has signed in once to your app, they will automatically be signed in anytime they reload it in their browser.
GoogleAuth.grantOfflineAccess() is indeed the method to call to get a code exchangeable for a refresh_token. However, in your use case, it seems that you would have to use both signIn and grantOfflineAccess which would ask the user to consent twice...
We are currently working on a feature in gapi.auth2 that would align more closely with the former gapi.auth.authorize behavior method and would be the right solution for your use case. I will update this thread as soon as I have more information.
GoogleUser.reloadAuthResponse() is used to get a fresh access_token, even if the previous one hasn't expired yet.
@TMSCH ok thank you, it's clear now. Do you have an ETA on when the new feature might be available? (btw, on a random note, we both went to Centrale Paris)
Small world! I can't provide a precise ETA for this feature unfortunately.
@fozzle @digggggggggg @santihbc @afterburn @phuwin @miltonhultgren @jbomeyer could you try again? We have fixed several issues and this may cover your use cases. If you still observe the issue though, could you please provide:
Thanks!
@TMSCH
GoogleUser.reloadAuthResponse() is used to get a fresh access_token, even if the previous one hasn't expired yet.
I'm using latest gapi and types but don't see this function on the GoogleUser object!?
@CHAZTATS could you show a snippet of your code? Once the user is signed in, this should work:
gapi.auth2.getAuthInstance().currentUser.get().reloadAuthResponse();
Hello, i am having a similar issue and when executing the code above, i get an error "noSessionBound"
Any clues?
Hi @mdelorimier, could you post a snippet of your code that reproduces the issue? Thanks!
@TMSCH sure but the issue seems to be session based.
For example, it does it with 2 of my users but not with the others. Also, deleting the authorisation or clearing the cookies cache does not seem to fix the issue.
@mdelorimier I am not able to reproduce the issue. I've signed in, reloaded auth response, then signed out of several of my accounts and it worked each time.
What browser are you using? Are you using incognito mode or something similar?
That is in chrome latest version. On the affected accounts, it works in incognito mode but not in regular mode (even if i have emptied the cookies, cache and all from the begining of time)
To be able to help you, I need more information. Could you give me step by step, what you are doing, what methods you are calling (and their parameters), until the issue observed? Thanks!
Hello,
Here is the sample code.
For the affected users, i always end up in the else branch of the setSigninStatus function.
function setSigninStatus(isSignedIn) {
var user = GoogleAuth.currentUser.get();
var isAuthorized = user.hasGrantedScopes(gApps.scope.join(' '));
if (isAuthorized) {
console.log('ok');
}
else {
console.log('not ok');
GoogleAuth.grantOfflineAccess()
.then(function() {
console.log(gapi.auth2.getAuthInstance().currentUser.get().reloadAuthResponse());
}, function(e) {
console.log(e);
});
}
}
updateSigninStatus = function(isSignedIn) {
setSigninStatus();
}
/////////////////////////////////////////////////
function onAuthApiLoad(bForce) {
var bImmediate = false;
if(!bForce && localStorage.getItem('gauthToken') == undefined ) {
window.gapi.auth2.setToken(gApps.oauthToken);
bImmediate = true
}
gapi.auth2.init({
'client_id': gApps.clientID,
'scope': gApps.scope.join(' '),
'immediate': bImmediate
})
.then(function() {
// GoogleAuth.signIn();
GoogleAuth = gapi.auth2.getAuthInstance();
window.gapi.auth2.getAuthInstance().isSignedIn.listen(function(signedIn) {
console.log(signedIn);
});
GoogleAuth.isSignedIn.listen(updateSigninStatus);
setSigninStatus();
}, function(error) {
console.log(error);
});
Thanks @mdelorimier for the snippet.
A couple comments:
'immediate' is not an option anymore in gapi.auth2. The init method will take care of automatically signing in any user that was previously signed in to the browser.window.gapi.auth2.setToken(gApps.oauthToken); should not work, this method does not exist (it uses to in GSI v1, however, as GSI v2 takes care of caching and refreshing token, it was removed)GoogleAuth.grantOfflineAccess() will not sign in the user to the current session. It will load an offline code that you can exchange in your backend for a refresh token. It assumes that you handle the session management, in your backend. Hence, reloadAuthResponse will raise a no_session_bound error.
If you want to sign in the user with the library, you have to call: GoogleAuth.signIn(). The default flow is popup based, so this call has to be triggered by a user interaction. If you don't want that, you can use the redirect mode (see ux_mode).
The behavior you are observing is working as intended. Could you update to using signIn instead of grantOfflineAccess to see if that solves your problem?
Ok
But event with this simple code, for some users, the login popup is displayed every single time :
function updateSigninStatus(isSignedIn) {
console.log('updateSigninStatus ', isSignedIn)
if(!isSignedIn) {
GoogleAuth.signIn()
.then(function() {
console.log(gapi.auth2.getAuthInstance().currentUser.get().reloadAuthResponse());
}, function(e) {
console.log(e);
});
}
// setSigninStatus();
}
function onAuthApiLoad(bForce) {
window.gapi.auth2.init({
'client_id': gApps.clientID,
'scope': gApps.scope.join(' '),
// ux_mode: 'redirect',
// redirect_uri: 'https://app-v2.patricemenard.com/'
})
.then(function() {
GoogleAuth = gapi.auth2.getAuthInstance();
GoogleAuth.isSignedIn.listen(updateSigninStatus);
updateSigninStatus(GoogleAuth.isSignedIn.get());
});
}
I have tried to delete the application in the problematic users without any success.
In that specific case, the updateSigninStatus does not get called for some reason.
Regards,
@mdelorimier there is no call to signIn in your snippet, so I can't tell you why it could cause the popup to be displayed every time.
The listener here will not be called initially, you have to do:
window.gapi.auth2.init({
'client_id': gApps.clientID,
'scope': gApps.scope.join(' ')
})
.then(function(a, b) {
GoogleAuth = gapi.auth2.getAuthInstance();
GoogleAuth.isSignedIn.listen(updateSigninStatus);
// Add this line.
updateSigninStatus(GoogleAuth.isSignedIn.get());
});
Even in that case, i am always getting false form GoogleAuth.isSignedIn.get(). The popup shows and hides imediately after being displayed.
Also, this if for a GApps domain, if that makes a diffrence.
I also have server and client auth for that specific app as i haven't found a way to properly do server auth then client.
Have you switched to using signIn instead of grantOfflineAccess?
Yes i have done that but still get the issue.
I have updated the code in my previous post. The promise from the signIn function never gets completed it seems.
here are the scopes :
["https://www.googleapis.com/auth/drive","https://www.googleapis.com/auth/userinfo.email","https://www.googleapis.com/auth/gmail.readonly"]
Is the popup opened? The browser can block them if they're not opened right after a user interaction. That would explain that the promise never resolves.
You should use the redirect mode if you want to avoid this issue, or add a button that the user will click and then synchronously call signIn.
Ok, found the issue, the chrome extension "privacy badger" was blocking cookies even if it was set to accept all for that specific site.
Feel kind of dumb now that i found this. Sorry for the disruption.
Thanks for your great explainations :)
@mdelorimier I'm glad you found the issue! I'll know for the next time that Chrome extensions can break the library ;)
No further comments on this issue, closing the bug. Please re-open if you are still observing cases where the call to signIn never resolves.
Wrapping signIn into a promise as suggested above worked for me in https://github.com/dblock/slack-sup/commit/b26d4706ff103a0637f8afb64aa8a1ed556d7597.
Promise.resolve(gapi.auth2.getAuthInstance().signIn()).then(function() {
}).catch(function(error) {
if (error && error.error == 'popup_blocked_by_browser') {
// A popup has been blocked by the browser
} else {
// some other error
}
});
Hey guys, working on a typescript-y implementation like this and came across this thread. The problem I had was resolved when I disabled privacy badger. I don't know exactly what it was trying to do but it looks like it prevented the assignment of cookies for the domain by the gapi.auth2 client.
If you're finding that sign in pop-up flow succeeds but no consequence is seen on your application, ensure that browser/extensions settings don't block cookie assignment.
Wrapping signIn into a promise as suggested above worked for me too
function wait(){
return new Promise(r => setTimeout(r, 300));
}
function updateSigninStatus() {
let GoogleAuth = gapi.auth2.getAuthInstance();
isSignedIn = GoogleAuth.isSignedIn.get();
if(!isSignedIn) {
let chain = Promise.resolve();
chain = chain.then(()=> {
return GoogleAuth.signIn()
}).then(wait);
}
}
Most helpful comment
Ok, found the issue, the chrome extension "privacy badger" was blocking cookies even if it was set to accept all for that specific site.
Feel kind of dumb now that i found this. Sorry for the disruption.
Thanks for your great explainations :)