google / google-api-javascript-client

Google APIs Client Library for browser JavaScript, aka gapi.
Apache License 2.0
3.2k stars 1.06k forks source link

Safari 11 "prevent cross-site tracking" breaking google sign-in for websites #342

Open duncanmcdowell opened 7 years ago

duncanmcdowell commented 7 years ago

It would appear that this Safari 11 "feature" is preventing this library from determining user identity when they return to my site. Before, gapi.auth2.init would return true for googleUser.currentUser.get().isSignedIn() (assuming the user is signed in and has already accepted the auth flow). Now, no signed-in user is returned, and worse, when going through 'signIn()', no values are returned.

Cross posted to stack overflow here

TMSCH commented 7 years ago

Hi @duncanmcdowell, thanks for reporting this issue. I have a couple more questions as I can't reproduce it myself on my setup (I cannot upgrade to High Sierra right now).

Does this issue happen if you:

  1. Open the page, sign in the user
  2. Close the page.
  3. In the same browser, open the page again

? Or do you need some time (>24hrs) between 2. and 3.?

Is there any console logs (errors)? when doing 1. or 3.?

duncanmcdowell commented 7 years ago

@TMSCH my apologies for not getting back to this sooner as I was away.

For the steps 1 thru 3, yes that will replicate the issue. As far as I can tell it is not necessary to wait any extended duration of time.

There are no console errors.

I can replicate the same issue when trying to write a review for a business from Google search results. A modal asks me to sign in to google to continue. After doing so, I see the same behaviour as I am experiencing in my own application: the authentication process begins by launching a small window/modal, and then silently fails. As expected, if I turn off the Safari option to "prevent cross-site tracking", I am able to sign in and write a review.

TMSCH commented 6 years ago

Thanks for the further details @duncanmcdowell. We are investigating the behavior as to decide on the best course of action.

peprasetya commented 6 years ago

I want to add this, as I have issue after I upgrade to iOS 11 and High Sierra.

I use gapi.signin2.render, when the browser only have 1 account to login, the onfailure is fired instead onsuccess. After the 'success' login (without the onsuccess being fired), clicking the Login button will open the login window again but then automatically close with onfailure being fired again.

I could make turn-around for my self, as I login to gmail, then add another account. So at least 2 Google Account login on the browser (mobile safari and desktop safari). Then the problem are all gone.

TMSCH commented 6 years ago

Thanks @peprasetya for the report. Intelligent Tracking Prevention doesn't play nicely at all with Single Sign-On services (see here) and we're trying to find the best solution.

duncanmcdowell commented 6 years ago

Any updates on this? I’m looking to roll out an app soon that relies on using google auth. I’d prefer not to ask Safari users to switch browsers

TMSCH commented 6 years ago

@duncanmcdowell the limitations are at the browser level, and cookies are required in the context of our library to securely authenticate the user. There's no way to work around the issue without asking the user to sign in again. If Google Auth is only used in your context to authenticate users (and you're not using it to authorize users) you could use cookies on your own domain to track the user's session state.

razor-1 commented 6 years ago

is there a plan to leverage https://webkit.org/blog/8124/introducing-storage-access-api/ in google sign in?

onyxblade commented 6 years ago

I don't know if it is the case. ITP blocks 307 redirections from getting correct cookies, but meta refresh is still capable to access to the cookies. This could be a workround and it works well in our application, although we are using an oauth-like system not google sign in.

TMSCH commented 6 years ago

@CicholGricenchos how are you using meta refresh in a client OAuth like setup?

@razor-1 it's a good idea we'll investigate.

onyxblade commented 6 years ago

@TMSCH We have two websites: S a central site and A a sub site. The first time when a user visits A, it needs to follow an A(entered url) -> S(generate_auth_code) -> A(consume_auth_code) -> A(entered url) redirection to get a session token from S's cookies. If we use 307 for redirections(for each ->), the A -> S cannot access to S's cookies and S -> A cannot access to A's cookies either.

Then we use meta refresh to replace the 307 redirections. The server returns a 200 and a html with a meta refresh tag containing a redirection url, which takes effect in 0.00001 second. This works just fine.

There are still differences between our case and another's. For example, our website didn't return 200 in the first place, which may trigger the 24 hrs rule of ITP since it may not consider 307 a user interaction. So it's still important to find out which step caused the problem in this thread exactly.

max-mykhailenko commented 6 years ago

with cookiepolicy: 'none', all works

auth2 = window.gapi.auth2.init({
    client_id: 'xxx',
    cookiepolicy: 'none',
  });

I don't know what exactly doing this, but it works

emanuel1025 commented 6 years ago

@TMSCH Hi. We can see this same issue at Qalaxia.

I am using Safari 11.0.2 on MacOS High Sierra 10.13.2.

This can be replicated by enabling Safari's "Prevent cross-site tracking" feature and accessing the website 24 hours after the user has logged out. Attempting to login after using attachClickHandler() or signIn() opens up an empty pop-up window which immediately closes. The success and failure callbacks are never called.

If Google Auth is only used in your context to authenticate users (and you're not using it to authorize users) you could use cookies on your own domain to track the user's session state.

What does this mean? In my case, the user is not logged in at all.

khaight commented 5 years ago

Is anyone still having this issue in Safari when "Prevent cross-site tracking" is enabled? When I isSignedIn.get() it always returns false.

    fetchBasicProfile: true,
    scope: 'profile',
    ux_mode: 'redirect',
    prompt: 'select_account',
    cookiepolicy: 'none'
godhoomrohit commented 5 years ago

This issue still persists in some version of Safari.

We are using "https://www.google.com/maps/api/js/reviews?key=" and google.places.reviews.createPublishReviewFlow for writing Google review via Google review widget. On safari, even if I am logged in, it asks to log-in and after clicking on "sign-in", login modal open, disappears and fails silently. It again asks login and this goes in loop.

It's already login but Google review widget is unable to figure out based on cookie.

Any fix available?

epitre commented 5 years ago

Hi, I also have this problem. Did you find any workaround ?

godhoomrohit commented 5 years ago

Hi, I also have this problem. Did you find any workaround ?

@epitre No solution found. For now we are redirecting our user to the url https://search.google.com/local/writereview?placeid= to write a review in Safari.

gkiely commented 5 years ago

I'm having this issue as well. cookiepolicy: none didn't work for me unfortunately. @TMSCH @grant

stayallive commented 5 years ago

This problem is still here and also breaks for when trying to get the user to use the Google Drive picker.

Our auth2 configuration is as follows:

window.gapi.auth2.init({
    client_id:           CLIENT_ID,
    scope:               'https://www.googleapis.com/auth/drive.readonly',
    fetch_basic_profile: false,
    ux_mode:             'redirect',
    immediate:           true,
    redirect_uri:        REDIRECT_URI,
    cookiepolicy:        'none', // Added later but has no effect
}).then((GoogleAuth) => {
    if (GoogleAuth.isSignedIn.get()) {
        handleAuthResult(GoogleAuth.currentUser.get());
    } else {
        GoogleAuth.signIn().then(function (GoogleUser) {
            handleAuthResult(GoogleUser);
        }, handleGoogleDriveError);
    }
});

GoogleAuth.isSignedIn.get() is never true or anything other than false causing infite auth / redirect loop since the user is authenticated with Google but that code on my redirect URL thinks it's not.

This works great on all other browsers but seems to be broken when in Safari. Any help/workaround/fix would be greatly appreciated since saying you can't use Safari doesn't boat well with most people 😄.

Dor256 commented 5 years ago

The problem is still here, I’ve tried to create a workaround by catching the error that the promise of signIn() throws. The thing is it’s as if Safari doesn’t recognize the sign in and gapi.auth2..getAuthInstance().isSignedIn.listen(callback) always passes false to the callback...

This works fine on other browsers and on Safari in private mode, a fix wold be much appreciated!

Edit: Disabling cookies and re-enabling worked eventually - just see that you wait approx 5 mins before reopening safari after re-enabling cookies!

wmaca commented 4 years ago

I am experiencing the same problem with Safari.

In a recent attempt, I changed the ux_mode to "popup", and it worked. It is really bad that Google left this abandoned for two years. If I had access to the codebase, I would be glad to fix it.

cor1 commented 4 years ago

I am still experiencing this problem. Pretty disappointing that it has been having this problem for so long

wmaca commented 4 years ago

From my investigation, when redirected back to the website, the client script reads the data from the URL and sends it to a hidden iframe for validation. As cookies are not allowed on that iframe, the iframe is unable to verify the information. Thus, the user is not authenticated.

I am not sure this is fixable. The workaround, as mentioned earlier, is to use popup as ux_mode. This way you don't get affected by Safari's cookie policy.

cor1 commented 4 years ago

@wmaca Unfortunately that still gives me the same problems on the latest ios safari

yuzhakovvv commented 4 years ago

See my comment here. May help in your case

mkannanmsc commented 4 years ago

This issue still persists in some version of Safari.

We are using "https://www.google.com/maps/api/js/reviews?key=" and google.places.reviews.createPublishReviewFlow for writing Google review via Google review widget. On safari, even if I am logged in, it asks to log-in and after clicking on "sign-in", login modal open, disappears and fails silently. It again asks login and this goes in loop.

It's already login but Google review widget is unable to figure out based on cookie.

Any fix available?

Could you please share the sample code for this (google.places.reviews.createPublishReviewFlow for writing Google review via Google review widget)

es-repo commented 3 years ago

@TMSCH Are you going to add support of Local Storage instead of relaying on Cookies in your library to avoid this problem?

TMSCH commented 3 years ago

Hi @es-repo, I am no longer working at Google and am not maintaining this repository anymore. Hopefully a current maintainer will be able to answer your questions!

matheusbaumgart commented 3 years ago

The popup workaround doesn't solve the issue on the latest versions of Safari, unfortunately. I'm also stuck on this.

es-repo commented 3 years ago

@matheusbaumgart Yep, seems Google doesn't care about this library at all. I had to switch to oidc-client-js library instead. It works pretty well.