Open SinusPi opened 6 years ago
@SinusPi what browser/version/platform are you encountering this issue under?
Chrome 62, Windows 10. I've just tested it to work correctly under Firefox Quantum 57; updating issue description.
... And right after having tested it on Firefox, it started working under Chrome as well. Sorcery, I tell you. I guess I'll come back when it breaks again...
Next time it happens, could you check the Record logs and the full console logs displayed?
Console logs only consisted of an Object with .error="unknown_error" that my console.log
call output, there was nothing else printed there at the moment of the pop-up call. I'll try the Record next time.
I have the very same error on chromium version 62.0.3202 , 63.0.3239 and 64.0.3282.119 when I copy past the hello world drive picker app from here https://developers.google.com/picker/docs/ : It works fine on Firefox and chrome 64.0.3282.119
{error: "unknown_error", status: {…}, g-oauth-window: Window, client_id: "id", cookie_policy: "single_host_origin", …}
client_id
:
"id"
cookie_policy
:
"single_host_origin"
error
:
"unknown_error"
g-oauth-window
:
Window
blur
:
ƒ ()
close
:
ƒ ()
closed
:
true
focus
:
ƒ ()
frames
:
null
length
:
0
location
:
Location {href: undefined, assign: ƒ, replace: ƒ}
opener
:
null
parent
:
null
postMessage
:
ƒ ()
self
:
null
top
:
null
window
:
null
response_type
:
undefined
status
:
{signed_in: false, method: null, google_logged_in: false}
__proto__
:
Object
Our existing integration has started firing this unknown_error
sporadically. It returns this error about 1/5 of the time.
@gregsabo could you provide a snippet of code that reproduces the issue? Would you have some Network logs to provide (esp. the ones to https://accounts.google.com/o/oauth2/...
)
@euri10 the snippet of code in this documentation is unfortunately both wrong and outdated... Apology for that. gapi.auth.authorize
is deprecated, gapi.auth2.authorize
should be used.
The call to this method, in the given snippet, would be:
gapi.auth2.authorize({
'client_id': clientId,
'scope': scope
}, handleAuthResult);
This method will open a popup: this has to be done synchronously after a user interaction, otherwise the browser can block the popup. Most commonly, this call has to be triggered after the user clicks a button.
localhost.txt Thanks @TMSCH I changed the call to api2 but I get the same unknown_error on chromium 64.0.3282.119 while on chrome same version it works fine. I go past the password and in the handleAuthResult function it now return this object (left side is chrome working fine, right is chromium), see the whole code below, maybe it's a misuse but it's still weird it works on kind of all borwser I tested but chromium.
<html>
<head>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.2.1/jquery.min.js"></script>
<script type="text/javascript">
// The Browser API key obtained from the Google API Console.
var developerKey = 'EDITED';
// The Client ID obtained from the Google API Console. Replace with your own Client ID.
var clientId = "EDITED";
// Scope to use to access user's photos.
var scope = 'https://www.googleapis.com/auth/drive.readonly.metadata';
var pickerApiLoaded = false;
var oauthToken;
// Use the API Loader script to load google.picker and gapi.auth.
function onApiLoad() {
console.log('before gap load');
gapi.load('auth', {'callback': onAuthApiLoad});
gapi.load('picker', {'callback': onPickerApiLoad});
}
function onAuthApiLoad() {
console.log('onAuthApiLoad');
window.gapi.auth2.authorize(
{
'client_id': clientId,
'scope': scope,
'immediate': false
},
handleAuthResult);
}
function onPickerApiLoad() {
console.log('onPickerApiLoad');
pickerApiLoaded = true;
createPicker();
}
function handleAuthResult(authResult) {
console.log('handleAuthResult');
console.log(authResult);
if (authResult && !authResult.error) {
oauthToken = authResult.access_token;
createPicker();
} else {
console.log('error');
console.log(authResult);
}
}
function createPicker() {
console.log('createPicker');
if (pickerApiLoaded && oauthToken) {
var docsView = new google.picker.DocsView()
.setIncludeFolders(true)
.setMimeTypes('application/vnd.google-apps.folder')
.setSelectFolderEnabled(true);
var picker = new google.picker.PickerBuilder().addView(docsView).setOAuthToken(oauthToken).setDeveloperKey(developerKey).setCallback(pickerCallback).build();
picker.setVisible(true);
}
}
// A simple callback implementation.
function pickerCallback(data) {
console.log('pickerCallback');
if (data[google.picker.Response.ACTION] == google.picker.Action.PICKED) {
var doc = data[google.picker.Response.DOCUMENTS][0];
folderid = doc[google.picker.Document.ID];
foldername = doc[google.picker.Document.NAME];
console.log(folderid);
$.ajax({
url: '{{ url_for('settings') }}',
data: JSON.stringify({
'folderid': folderid,
'foldername': foldername
}),
type: 'POST',
contentType: 'application/json',
success: function (response) {
console.log(response);
console.log('success');
$('#update-div').html('Folder set to ' + foldername + ' with id ' + folderid);
},
error: function (error) {
console.log(error);
}
});
}
}
</script>
</head>
<body>
<div id="update-div"></div>
<!-- The Google API Loader script. -->
<script type="text/javascript" src="https://apis.google.com/js/api.js?onload=onApiLoad"></script>
</div>
</body>
</html>
edit: added localhost.har renamed as txt file localhost.txt file for the failing chromium, if that helps
@euri10 thanks for the snippet of code and the HAR, it's very helpful. It seems that the library doesn't properly initialize, as I can't see some specific requests in the HAR file.
I tried your code with Chromium on Debian. The popup was blocked upon opening the app (which is expected). When manually triggering onAuthApiLoad
from the console, I can successfully authorize the user. I'm using Chromium Version 66.0.3336.0 (Developer Build) (64-bit).
However I can reproduce your error after enabling "Block third-party cookies" in Settings. gapi.auth2
does not currently work when this option is enabled. Is it the case for you?
@gregsabo it might be due to third-party data blocked. Do you know if your user base could sometimes have this setting enabled? Enterprise users maybe?
@TMSCH thanks, the Block third-party cookies indeed is what caused the unknown_error for me, unsetting it (it's enabled by default on chromium, no idea on other browsers) solves the issue !!
@TMSCH I doubt blocking third-party cookies is the culprit since users who have successfully logged in to our app with Google for months are suddenly reporting this problem. We've confirmed that users are having trouble in Chrome, Firefox, and Edge.
@gregsabo are you using gapi.auth.authorize
library? Or gapi.auth2.authorize
?
If so, please provide a snippet of code with the configuration of the call you make. Thanks!
Is there any chance I could try a live URL of your app? We made some changes in gapi.auth.authorize
that might have created this issue so debugging myself would be very useful.
Here's a live URL:
When the bug happens, we display "Google Authentication Failed" in a pink box on the login screen.
We're using gapi.auth.authorize
. I'll work on getting the snippet. Do you mean the client ID and such?
Actually, here are some easier steps to reproduce:
@gregsabo I get to that screen with the error message you mention after closing the popup once or twice. It seems that the login page triggers it when the call to gapi.auth.authorize fails.
A recent change we made starts exposing a popup_closed_by_user
error. It was previously silently ignored. It seems to be the case here, not an unknown_error
.
@gregsabo are you still observing the unknown_error
? We pushed changes that should expose more info on the error.
@TMSCH We're noticing a new error now, so I guess that's promising!
We had a developer here run into the bug, and it reproduced consistently in his browser. The error returned by gapi.auth2.authorize
(yes, we upgraded to auth2
) is "user_logged_out"
. This is pretty surprising because the user is logged into multiple accounts. They are able to successful select an account (They are not prompted for password because they are already logged in.), but when the popup closes, the response returned in the callback indicates the user is logged out.
We played around with the prompt
argument and found that, if "none"
is specified, we get an "immediate_failed"
error with subtype "no user_bound"
. The user has definitely authenticated. They're able to access Google services in their browser. They are not asked for a password when choosing an account in the Google auth popup.
This developer claims that they were able to solve the issue by clearing just their asana.com cookies. This seems really weird. The odd behavior we're seeing is entirely isolated to gapi
.
If you have an idea what might be going wrong, we'd really appreciate it.
The issue doesn't reproduce consistently, but feel free to use https://app.asana.com/-/login?use_gauth2=true to try out this auth flow. (That query parameter is necessary since we've switched back to the redirect-based flow for our users as mitigation for this issue.)
Thanks for upgrading to auth2!
The prompt: 'none'
raising immediate_failed
if the popup flow didn't work makes sense. I'm very surprised by the error though after the user goes through the popup flow.
I can't reproduce it myself, but next time it happens, could you check the Console logs for requests to https://accounts.google.com/o/oauth2/iframerpc?...
, especially for ?action=issueToken
or ?action=listSession
, and let me know what the content of the request as well as the response are?
Thanks!
@TMSCH I appreciate the response! We were able to reproduce the issue internally again.
I set a breakpoint on window close and checked preserve logs. Only one request showed up in the network tab—a request to https://accounts.google.com/_/signin/oauth
. I didn't see the things you mentioned.
BUT, the error response we received this time was different! I'm fairly sure this is the same issue, so I'm assuming something changed in the error reporting in the server-side code.
{error: "immediate_failed", detail: "Not all scopes are approved.", thrown_by: "server"}
This is a super interesting error response since the only scopes we're requesting are "email" and "profile". AND, when I repeat the call to authorize
omitting the "profile" scope, it succeeds!
It's not actually clear to me what this error message indicates. I thought "profile" and "email" were available to all client ids. It also seems super duper bizarre to me that our login issue is spurious, both in that most users don't see it and in that most users that see it don't see it consistently.
If you have further insight, I'd really appreciate it. Thanks so much!
@jadengeller-asana hmm this error can happen for several reasons. If you sign in, revoke the scopes in myaccount.google.com, then come back to the app and ask for prompt: 'none'
it could raise this error. However it wouldn't work if you ask for email right after. Could I see a snippet of code that shows the calls to gapi.auth2.authorize
? And what it was, before the migration?
Are previously signed in users (without revoking scopes) able to sign in with gapi.auth2.authorize
? Or are all facing the issues you're having?
I was manually running
gapi.auth2.authorize({ client_id: "OUR_CLIENT_ID_HERE", scope: "profile email" }, function(x) { console.log(x); })
in the JS console in Chrome.
Are previously signed in users (without revoking scopes) able to sign in with gapi.auth2.authorize?
I don't believe the users having these issues revoked any scopes. I can confirm that profile
was failing while email
was succeeding since I was able to meet with a user with a repro.
@jadengeller-asana had you clear the cache when running these tests?
Could you send me the HAR of the network requests made when reproducing the issue so I can check what could be wrong?
Hello, to emphasize this, I seem to be encountering the same issue. It pops up the signIn modal via calling:
GoogleAuth.signIn()
I select one of my accounts, modal closes and I see in network calls:
{"error":"USER_LOGGED_OUT","detail":"No active session found."}
from:
https://accounts.google.com/o/oauth2/iframerpc?action=issueToken&response_type=token...
It's a 200 OK, no exceptions thrown, no promise resolved from signIn().then.
@indrekru do you have a snippet of code or a live app so I can reproduce the issue?
Hey again, figured out what's going on. I have Ghostery browser extension, which seems to mess with your client library flow. Sorry for maybe causing too much alarm. BUT here's my fundamental question: How can I ensure my customers 100% working login flow, if I don't know what browser extensions might be messing with the HTTP traffic? I also tried adblock, that one works. So I have no overview whatsoever what else might be out there and what it might be doing with your client flows.
Seems the only sensible thing to do is to fallback to the redirect flow. Or am I wrong?
@indrekru thanks for finding the culprit! It is very difficult to ensure it works if some browsers extensions are messing with the HTTP Traffic in such a way. IMO, this is an issue with the extension, not the library. I also use adblocker and never had any problems. I'd suggest bringing the issue to the author of Ghostery.
had you clear the cache when running these tests?
I don't think we did. Why does this matter?
While running manual testing on the library, especially when changing scopes and other config, it can sometimes lead to some edge cases due to caching that are basically not observable in production apps were configuration is stable.
Okay, I'll be sure to clear the cache next time I observe the issue.
Could you send me the HAR of the network requests made when reproducing the issue so I can check what could be wrong?
I have a textual copy of the headers from the POST request to https://accounts.google.com/_/signin/oauth
, but I didn't save a HAR. If that's useful, I'll send it over (how?). If not, I'll collect a HAR when I again have access to a repro.
I asked one of our repro users about any interesting browser extensions they have installed. They mentioned Privacy Badger. It seems very likely that could be causing issues here.
@jadengeller-asana did you manage to see whether Privacy Badger was the culprit of the issue?
Not yet, but there's at least 2 distinct issues here. One repro user gets a "Not all scopes are approved." and another repro user gets a "user_logged_out" error. The Privacy Badger extension is installed for the latter user.
@jadengeller-asana the "Not all scopes are approved" might be due to the fact the user had already signed in with GSI v1 but it's surprising. I'd need the network requests of calls to https://accounts.google.com/o/oauth2/iframerpc to debug, would you have them?
I only recall seeing requests to https://accounts.google.com/_/signin/oauth, even when I preserved log. Am I mistaken?
That's very surprising, at least one call to the URL I mentioned is required, and is done right after the IFrame is loaded on the page.
Oh, I think I only started recording network activity after that point (since I cannot open the developer tools before the page is opened). I guess I'll have to use something other than Chrome developer tools.
You can open the tool and then redirect to your page. Those calls happen in the main window, not the popup.
@TMSCH I probably have the same issue: Using this snippet:
window.gapi.auth2.authorize({
client_id: CLIENT_ID,
scope: 'profile email',
response_type: 'id_token permission'
}, (response) => {
// Here...
// response.error === 'user_logged_out'
});
Also tried to use signIn()
, and it returns promise which never resolved/rejected. The device is iOS/Safari. Tried in Safari/"incognito" – works. Tried in iOS/Chrome – works. And some days ago i remember i was able to login in iOS/Safari, but looks like something happened and now it is not working. Maybe it is related with multiple Google accounts that i have logged in inside iOS//Safari (one personal and one work), and the personal one was logged out (maybe expired), but internally you checked the other one which is logged in and not expired, but returned a token to the one which was logged out which is not working... Something like that, just a guess :)
Here is the output from iframe, if it can help (i replaced actual id_token and domain to a placeholder):
window.addEventListener('message', function(event) {
console.log(event.data);
});
[Log] {"method":"fireIdpEvent","params":{"type":"idpReady"},"rpcToken":"379831079.4531398"} (vendor.js, line 39)
[Log] {"id":"568-82480.7010874615","result":true,"rpcToken":"379831079.4531398"} (vendor.js, line 39)
[Log] {"method":"fireIdpEvent","params":{"type":"authResult","clientId":"137802694133-hapokd2n5ktivbpfb7oehgre4bhd4usp.apps.googleusercontent.com","id":"auth848489","authResult":{"id_token":"<id_token_here>","login_hint":"AJDLj6K83uPn1JhzuwTegx9N1-BA8V4khmiQP0sUt6SFvvCkpLPQLrdIpZ22GRhMqaX9Q3VyyK6ZN8PwJv1i-NE0v5XwXrpDs71sWpy6sdhDomnX4Y994O0","client_id":"137802694133-hapokd2n5ktivbpfb7oehgre4bhd4usp.apps.googleusercontent.com"}}} (vendor.js, line 39)
[Log] {"id":"638-527205.5765403978","rpcToken":"379831079.4531398"} (vendor.js, line 39)
[Log] {"method":"fireIdpEvent","params":{"type":"sessionSelectorChanged","newValue":{"hint":"AJDLj6K83uPn1JhzuwTegx9N1-BA8V4khmiQP0sUt6SFvvCkpLPQLrdIpZ22GRhMqaX9Q3VyyK6ZN8PwJv1i-NE0v5XwXrpDs71sWpy6sdhDomnX4Y994O0","disabled":false},"domain":"https://mydomain.com","crossSubDomains":true},"rpcToken":"379831079.4531398"} (vendor.js, line 39)
[Log] {"id":"641-316556.7442235234","result":true,"rpcToken":"379831079.4531398"} (vendor.js, line 39)
[Log] {"id":"644-33757.89449158148","result":{"error":"user_logged_out"},"rpcToken":"379831079.4531398"} (vendor.js, line 39)
@TMSCH I got the HAR! Is there a way I can share it with you without posting it here? I don't want to accidentally share personally identifiable information publicly.
Really interestingly, gapi.auth2.authorize
failed with the error popup_closed_by_user
but gapi.auth.authorize
succeeded. Maybe we shouldn't have upgraded...
@c58 , this is a bit beside the point, but you might want to be careful about that (response) => { }
lambda function there; IE still doesn't support that.
@SinusPi it is transpilled with Babel, but thanks for the precaution anyway ;)
@TMSCH Are you still interested in checking out the HAR? We'd really appreciate understanding what's going wrong. We've stopped using this library (and the popup-based flow) in production entirely for the time.
We've been able to somewhat isolate what Google-set cookies that are causing the issue.
One user with the issue deleted the following cookies one at a time, and Google SSO started working after the final cookie was deleted:
_lc.vistior
(id censored)_qca
_utma
Another user with the issue didn't have the _utma
cookie, so I asked the follow the same exercise of deleting Google-set cookies one at a time. They deleted the following, and things started working after the final cookie:
_lc.vistor
(id censored)_ga
Hopefully this information is useful in debugging the issue.
I have this problem too in Xiaomi Mi UI OS (Xiaomi Redmi phones). Using the Google Chrome app I am able to use the Google Picker correctly.
But if I change to the OS native browser (it is a very decent browser), Google Picker will not launch. It just keeps returning "user_logged_out". I've played around a little bit but could not find a solution.
Dropbox Integration with Chooser works very well on all platforms. I can't understad why Google Picker is so bugged.
As soon as I call
gapi.auth2.authorize
, it opens a pop-up AND calls the callback with an unknown_error, instead of waiting for the result of the pop-up. Also, there doesn't seem to be a way to useux_mode:"redirect"
with.authorize()
, is there?The (simplified) code I'm using is:
This fails under Chrome 62 under Windows 10. Works correctly under Firefox Quantum 57, though.