nraboy / ng-cordova-oauth

AngularJS oauth library for use with Apache Cordova projects
https://www.thepolyglotdeveloper.com
MIT License
456 stars 199 forks source link

Google will no longer allow OAuth requests to Google in embedded browsers #283

Closed jdnichollsc closed 7 years ago

jdnichollsc commented 8 years ago

Hi Nic,

What do you think about the following link? https://developers.googleblog.com/2016/08/modernizing-oauth-interactions-in-native-apps.html?m=1

Regards, Nicholls

nraboy commented 8 years ago

Support for Google Oauth will more than likely be dropped in ng-cordova-oauth. The goal of this library was to use the consistent Oauth spec to prevent having to mess around with X number of native provider SDKs.

It is a lot easier to work with a formal spec and support X number of providers than it is to work with X number of very different SDKs.

Best,

WilliamDenniss commented 8 years ago

No need to drop support – Google still supports 100% standards-based OAuth for native apps, no native SDK needed. We're just ending support for embedded browsers (i.e. web-view) as a way to do OAuth, since it's not as user friendly or secure.

You can set InAppBrowser to use the system browser like so:

cordova.InAppBrowser.open('https://accounts.google.com/…', '_system');

You'll also need to register your app for the custom URI scheme OAuth redirect (on iOS, macOS, Android, and Universal Windows Platform). If you're using a platform where this callback is not possible, then it's OK to continue to use embedded browsers for OAuth to Google on those platforms for now.

As a UX upgrade on the system browser, it's advisable to use in-app browser-tabs when available (this is especially important on iOS, as it's frowned upon to open mobile Safari for sign-in). We released a library recently to help with that: https://github.com/google/cordova-plugin-browsertab. See the sample code in the README that includes fallback handling (so on compatible versions of iOS and Android it would open the browser tab, otherwise it will revert to the system browser).

Not all OAuth providers support this improved method of OAuth for Native Apps, but more and more are doing so, so you can upgrade each as they support it.

I understand this is a bit of work to switch over, but note that there is a large user benefit if you do: your users won't have to sign-in to Google again to use your app! Users who are already signed-in to Google will be able to tap a single button and get in! Users who are not signed-in will have to sign-in to Google for the first app they use, but then won't have to again for subsequent apps. This should increase the conversation rate of your sign-in flow dramatically (our user research shows a lot of people abandon the sign-in completely when they have to sign-in from scratch, as is always the case with web-view).

nraboy commented 8 years ago

I am pretty certain the system browser will not work because the event handlers don't work the same in Apache Cordova. If the host application cannot anticipate the end of the login flow, extract the token, and close the browser, then it will not work.

I have no plans to support each and every native oauth SDK for every provider. If the InAppBrowser no longer functions for a particular provider, that provider will be removed. My reasoning for this is that only a small percentage have Apache Cordova plugins and I have no intention of making plugins for the providers that don't.

@WilliamDenniss if you work for Google (sounds like you do), I encourage you to submit a PR to this project fixing Google support. This is a heavily used library and it will prove how accommodating Google is to the platforms they disrupt.

Also, unless I'm missing something, I don't see how removing web-view support makes oauth any more secure. Implicit grant types were meant to be done in client facing interfaces. I can see from a friendliness perspective, but I don't really agree with the secure part that Google is selling (unless I'm missing something).

cnadeau commented 7 years ago

@WilliamDenniss : How would you close that system browser and get back to the app?

@nraboy is right, the support required for OAuth (loadstart for the redirect url) for system browser does not seem to be available for that scenario:

addEventListener

Browser Quirks loadstart and loaderror events are not being fired.

I validated the InAppBrowser browser plugin (we were actually using) and no events were fired using cordova-plugin-inappbrowser 1.5.0 on an iPhone 6 / iOS 10

WilliamDenniss commented 7 years ago

In general terms, the OAuth provider redirects the user (in the system browser) to a custom URI scheme claimed by the app, which opens the app. The Authorization Response URL is provided to the app by the OS when it opens. The app can then process the authorization response URI as before.

I have personally tested this flow using custom URI schemes on iOS, Android and UWP (with native sample apps, not cordova apps). I believe there should be a way in Cordova to receive the redirect URIs when the app is opened in this manner.

I found the instructions to handle custom URI schemes for Codova on iOS here. This solution looks appropriate for receiving Android intents.

nraboy commented 7 years ago

Google support was removed from the library in https://github.com/nraboy/ng-cordova-oauth/commit/555b5caafbe0b7a552c6dc418e3353f6615f24da. The preferred way to use Google now is to use the native Apache Cordova plugin.

Best,

ghost commented 7 years ago

Users who are not signed-in will have to sign-in to Google for the first app they use, but then won't have to again for subsequent apps.

@WilliamDenniss What if I don't want the user's Google credentials saved on the device for whatever reason? Is there still a way around it?

iconico commented 7 years ago

Try this plugin for Google Auth instead https://github.com/EddyVerbruggen/cordova-plugin-googleplus

santekotturi commented 7 years ago

once I've moved over to another system (still unclear what "the native Apache Cordova plugin" is), will my users who've signed in via Google be able to login via the new system or will I need to migrate their accounts ?

trustedjohn commented 7 years ago

I have a Cordova iOS app whose resources (js, CSS, etc...) reside on a remote server and I use the Firebase 2.x SDK (authWithOAuthPopup) to authenticate once, then it automatically caches the token and prevents future oauth popups. I want my app (an email app) to remain logged in to the Google account that the user originally auth'd, even if they log in to a different google account somewhere else. Will this change 1) prevent me from using Firebase's auth popup after April, and 2) log my app's user out of the their gmail account if they subsequently log in to different google account in another app?

slayer3600 commented 7 years ago

A workaround to this problem is to add this to your config.xml. It prevents Google from detecting the request is from a mobile app. It worked for me.

<preference name="OverrideUserAgent" value="Mozilla/5.0 Google" />

chr4ss1 commented 7 years ago

@slayer3600 it indeed works but it stops Ionic adding platform specific classes on CSS, and also ionic.Platform.isIOS() and ionic.Platform.isAndroid() start returning false, and other few annomalies - so be careful :P

There is a way to download cordova-useragent plugin, and do something a long of the lines:

cordova
  .setUserAgent("my temp agent")
  .then(() => oAuth.googleLogin())
  .finally(() => cordova.resetUserAgent());

but the cordova-useragent plugin itself is outdated

jdnichollsc commented 7 years ago

@nraboy with the solution of @slayer3600 you can add google again, what do you think?

nraboy commented 7 years ago

Google has dropped support. I don't think it is appropriate to add a hack to get it working. As @ChrisEelmaa mentioned, there are other problems it brings up. You're setting yourself up for problems by hacking it together.

If you want Google support, I suggest using a native SDK alternative.

alxanthony commented 7 years ago

@slayer3600 thanks! that did the trick for me, it might not be the best solution but it buys you time to implement something more stable.

I don't use iconic but my app is made with angular, and angular material as a css framework and everything is working correctly with this trick.

FPSE commented 7 years ago

@ChrisEelmaa tried that, but that plugin doesn't seem to work. UserAgent.set("Mozilla/5.0 Google") results in unrecognized selector sent to instance So my app is broken currently. Angry mails incoming..

chr4ss1 commented 7 years ago

@FPSE yes I know that's why I said that plugin itself is outdated.

Also one warning is that OverrideUserAgent is not shown as supported for iOS on the latest docs: https://cordova.apache.org/docs/en/latest/config_ref/index.html

You will see that AppendUserAgent is shown iOs/Android both, but not the Override one.

That said, I use Satellizer to do the authentication, and it used InAppBrowser as well for login flow, fortunately, it was relatively easy to replace the inAppBrowser pop ups with native ones, as the code is quite good. After all, native authentication and the InAppBrowser flow is the same - only one has more functionalities and is better.

I don't know if this will help, but maybe ng-cordova-oauth has the same way - is there a way to replace the google popups with native popup?

You can see more @ https://github.com/sahat/satellizer/issues/1029 where I show the code (I use cordova-plugin-googleplus)

jmcrthrs commented 7 years ago

@WilliamDenniss Using system browser combined with a custom URL scheme works a treat. Thanks!

Update 10 May 17: Apple rejected the application with the following message

We noticed that the user is taken to Safari to sign in or register for an account, which provides a poor user experience. Specifically, the user is linked out to Safari while creating an account through Google+.

To resolve this issue, please revise your app to enable users to sign in or register for an account in the app. We recommend implementing the Safari View Controller API to display web content within your app. The Safari View Controller allows the display of a URL and inspection of the certificate from an embedded browser in an app so that customers can verify the webpage URL and SSL certificate to confirm they are entering their sign in credentials into a legitimate page.

jdnichollsc commented 7 years ago

Guys, check my example using Firebase and cordova-plugin-googleplus https://gist.github.com/jdnichollsc/17bae6581d405321937fe433410172c9

Also you can check the comparative with the old way using ng-cordova-oauth Regards, Nicholls

beanspatil commented 7 years ago

Does anyone have a fix incase we have Keycloak in between? We are using an ionic based app which does google auth via keycloak.

m-vdv commented 7 years ago

How to handle an OAuth situation like trakt.tv has?

Trakt.tv provides a login screen which has Email/Pass, Facebook, Twitter and Google sign-in capabilities. I'm using ng-cordova-oauth and everything works fine, except when a user tries to sign-in with Google from the trakt.tv OAuth screen (which is loaded in the WebView). More info: http://docs.trakt.apiary.io/#reference/authentication-oauth

It appears I would have to load the trakt.tv OAuth screen (which has the google sign-in button) from the system Chrome/Safari app but as @jmcrthrs pointed out, Apple doesn't like that.

So what options do we have left?

Some of my app users are complaining, since they can't login with Google anymore...

jmcrthrs commented 7 years ago

@m-vdv https://github.com/EddyVerbruggen/cordova-plugin-safariviewcontroller

I'm going to use this plugin for iOS (and stick with system browser for Android)

setheen commented 7 years ago

@m-vdv, you've described our situation perfectly. We use Auth0 as our identity provider. They host a login page that contains multiple provider options (Google/Facebook/Email+Pass). Historically, we'd use inappbrowser to navigate to the Auth0 login page. Today, we use cordova-plugin-safariviewcontroller (for both Android and iOS) to hit that Auth0 login page using PKCE. This works for most use-cases but there's some gotchas:

  1. Neither Facebook or Google allow you to login without cookies being enabled. Because cordova-plugin-safariviewcontroller relies on the default system browser, users can disable cookies, leading to a poor login experience.
  2. cordova-plugin-safariviewcontroller relies on Chrome custom tabs for Android. If your default browser wasn't Chrome, it wouldn't work. I actually submitted a PR to search for all installed browsers so we could warn the user if Chrome wasn't installed. If you're using an older version of the plugin, you may want to update.
  3. To provide a better user experience, we programatically check for cookie support to warn the user they should enable cookies before logging in. Our app temporarily hosts a web server at localhost that immediately redirects back to our app (using url scheming) to report back if cookies are enabled on the system browser using a small amount of javascript. We've found that some antivirus programs such as Total AV do not like custom scheme redirects, IE "UNKNOWN_URL_SCHEME"s.

We still have users reporting occasional login issues as Android fragmentation pops up to bite us. Hoping to see some evolution when interoping with system browsers in the future

m-vdv commented 7 years ago

Since my app is Android only (for now). I've implemented the system browser method. This article was quite helpful: https://medium.com/@jlchereau/stop-using-inappbrowser-for-your-cordova-phonegap-oauth-flow-a806b61a2dc5

If anyone would be willing to share a working example (or tutorial) for the cordova-plugin-safariviewcontroller method proposed by @setheen that would be great!