_From phenome on March 27, 2012 11:47:59_
What steps will reproduce the problem? 1. Fire gapi.auth.authorize(). Wait for popup to open
When you DENY the authorization, the callback gets called with null.
::: Reading the API I assumed it would get called with a token object with the error parameter set. Is it really misleading or my interpretation is lacking?
I actually have no problem with it being called with null, but since there are two cases (the user actively DENYING authorization, or simply closing the window), it would be nice to get a token object with an error describing what happened.
_Original issue: http://code.google.com/p/google-api-javascript-client/issues/detail?id=23_
_From [email protected] on May 07, 2012 11:47:56_
Status: Accepted
Owner: [email protected]
_From [email protected] on July 20, 2012 09:54:21_
This is just to be polite and say goodbye to a customer who just slammed the door - I mean "closed the window".
_From [email protected] on August 02, 2012 09:52:38_
Labels: Milestone-GA
_From [email protected] on September 30, 2013 02:36:25_
There are 2 issues here:
Someone at google willing to help and get this fixed after over a year? Or where is the source code of this stuff?
BTW: the docs are 'a bit' outdated and referring to this blog here (?) http://google-api-javascript-client.blogspot.de/
_From [email protected] on November 23, 2013 15:24:00_
I think issue #74 and #23 are related.
_From [email protected] on May 29, 2014 20:36:14_
2 years later and no word.
Anyway I don't think this feature is needed. If a user closes the login popup they can just click the login button again (just don't hide the login button until you have a user token). Also if they click the login button multiple times it just focuses the single popup.
_From [email protected] on May 30, 2014 00:06:06_
I would rather say that this future is nice to have. Why do some workarounds, not always nice and often not giving what we really want to achieve.
This doesn't make for a great experience. Would be awesome to see this one fixed.
Currently you can detect when the user clicks cancel by checking the error message in the authorization response. Demo here: http://wheresgus.com/secondchance/
You cannot detect when the user closes the window.
Checking whether the window has closed turns out to be pretty trivial.
Here's a demo: http://jsbin.com/wuxinoruze/1/
And here's a workaround. It'll fire whenever any opened window is closed. It works in the authSample.html page.
You could check the url contains google.com if your page opens windows for some other reason. (or hold a reference to the real window.open)
(function(wrapped) {
window.open = function() {
var win = wrapped.apply(this, arguments);
var i = setInterval(function() {
if (win.closed) {
console.log('closed!');
clearInterval(i);
}
}, 100);
};
})(window.open);
Hi @broady, I appreciate the help here! Its great that we can detect the window close though Im not sure if this can detect the difference between a successful closing of the dialog when auth succeeds or when the user closes the page.
I have enhanced the workaround by @broady to match @i386 's issue.
Instead of reacting to the "window.closed" state directly, I simply cancel the
deferred object. Cancelling an already-resolved promise will not have any effect.
However, it does reject the deferred and therefore invokes the onReject handler.
var authorizeDeferred;
function onClickLogin() {
(function(wrapped) {
window.open = function() {
// re-assign the original window.open after one usage
window.open = wrapped;
var win = wrapped.apply(this, arguments);
var i = setInterval(function() {
if (win.closed) {
clearInterval(i);
// cancel has no effect when the promise is already resolved, e.g. by the success handler
// see http://docs.closure-library.googlecode.com/git/class_goog_Promise.html#goog.Promise.prototype.cancel
authorizeDeferred.cancel();
}
}, 100);
return win;
};
})(window.open);
authorizeDeferred = gapi.auth.authorize({
// ...
}).then(onAuthResult, onRejected);
}
@Lukx the problem with that approach is that it assumes a successful authorization from Google gets back to us before the interval timer is run. So basically the code has two issues: First, we check at a resolution of 100ms but there is no guarantee that we check 100ms after the window closes. Second, it assumes Google gets back to us quickly.
The solution for first is to debounce the cancel() call by some reasonable amount of time (say 1 second?) so that Google has a chance to resolve the promise before we reject it.
The solution to the second would require some internal knowledge of when user successfully clicks before the network reqs to Google happens for the authorization.
This issue still exists in the auth2 client (https://developers.google.com/identity/sign-in/web/reference), which uses promises. I would expect that clicking 'deny' or closing the window would resolve the promise with an error. However, neither the success or error methods of the promise are called.
FWIW, @Lukx's workaround seems to work pretty well.
Yea, why fix bugs when we can just bloat our code with workarounds!
The bug is still present :(
Please try the newer gapi.auth2 API and let us know whether the problem persists
@bsittler yep, the problem persists :(
My code is pretty simple:
gapi.load('auth2', () => {
gapi.auth2.init({
scope: this.scope,
client_id: this.clientId,
cookie_policy: this.cookiePolicy,
fetch_basic_profile: this._fetchBasicProfile,
hosted_domain: this.hostedDomain,
openid_realm: this.openidRealm
});
});
On click event handler:
gapi.auth2.getAuthInstance().grantOfflineAccess( {'redirect_uri': 'postmessage'} ).then(
( authResult?: GoogleSignInSSAAuthResult ) => this.onSignIn( authResult ),
() => this.onSignInError() );
No matter what I do (click Deny button, close window) error handler never fires so as onSignIn. If I click Approve button onSignIn fires as expected.
Thanks for the report, I've passed it on to those working on gapi.auth2.
Just noticed exactly the same behavior as @DarkSilence
Hi @DarkSilence, we are working on a fix, I will update this thread when it is released.
Hi @DarkSilence @renarsvilnis @neilsoult @alalonde @Hengjie @Lukx @i386 @broady @gguuss, the fix has now been released for gapi.auth2! signIn and grantOfflineAccess promises will be rejected if:
Thanks for your patience! Could one of you make sure you observe that it works, so I can close this issue?
Hello @TMSCH I don't see this working for me.
GoogleAuth.grantOfflineAccess()
.then( response => {
dispatch( signUp() )
})
.catch( error => console.log(`ERROR —— GAPI AUTH —— ${error}`) )
I get an error saying that there's no catch function. is that normal?
@bernatfortet it is not normal, the catch function should exist. What does dispatch(signUp()) do? Can you post the full stack trace of the error?
Dispatch is part of Redux, it returns a promise, could that be problematic?
I've solved the issue by doing the following:
GoogleAuth.grantOfflineAccess()
.then( response => {
myFunction()
}, error => {
console.log(`ERROR —— GAPI AUTH —— ${error}`)
})
@bernatfortet it could be... The best way to know would be to not use it in the resolution callback of the grantOfflineAccess returned Promise (i.e. completely remove the dispatch( signUp() ) line and try again)
Most helpful comment
This issue still exists in the auth2 client (https://developers.google.com/identity/sign-in/web/reference), which uses promises. I would expect that clicking 'deny' or closing the window would resolve the promise with an error. However, neither the success or error methods of the promise are called.
FWIW, @Lukx's workaround seems to work pretty well.