auth0 / auth0-cordova

Auth0 integration for Cordova apps
MIT License
49 stars 66 forks source link

Does not work with WKWebView on iOS #42

Closed MT-- closed 6 years ago

MT-- commented 6 years ago

Using this is a recent Ionic(3+) project, I came to notice that the plugin did not route the success callback or dismiss the SafariViewController after I added the "official" Ionic WKWebView plugin. This may be due to the fact there there is a local webserver being used to serve files and the file:// protocol is "not allowed" (though I have gotten it to work on iOS 10). I would say that it might be a CORS issue, since Auth0 domains likely have restrictions.

The Auth0 console shows a successful login, but the view does not move past accounts.google.com/...

screen shot 2017-05-30 at 1 58 21 pm img_0020

darkyen commented 6 years ago

Hi MT-- you'll need to set your "Client Type" to "Native" For the request to work in https://manage.auth0.com/#/clients > Your client name > settings

MT-- commented 6 years ago

@darkyen it is set to "Native." It works perfectly with the older UIWebView class as its webview controller.

darkyen commented 6 years ago

I just read the logs, can you check if you have *****.auth0.com added to the domains that your app can make request to in your ionic/cordova configuration?

MT-- commented 6 years ago

@darkyen for development purposes, I have allowed allowed navigation and access to any URL in my configuration(s).

darkyen commented 6 years ago

That is weird, the initial error seems to fail at the client side and not the sever, would it be possible for you to share a minimum reproducible.

MT-- commented 6 years ago

Yes, do you have a test domain/client that you would like me to point it to? @darkyen

darkyen commented 6 years ago

Nope (: I can configure them to my own clients and test, I'm mostly interested in the exact setup of things.

MT-- commented 6 years ago

Also, if you build the "Ionic 2+ SDK Quickstart" from the site and add the WKWebView plugin, it should reproduce this issue.

This example (with updated credentials) also fails with the WKWebView plugin added.

https://github.com/driftyco/cordova-plugin-wkwebview-engine

MT-- commented 6 years ago

https://github.com/MT--/auth0-wkwebview @darkyen

darkyen commented 6 years ago

I reproduced it, thanks. I'm working on it atm.

saschwarz commented 6 years ago

I think I have the same problem. But I don't see this issue in the iOS emulators, only on physical devices. It also occurs when using database logins on iOS physical devices.

saschwarz commented 6 years ago

I just saw this issue that might shed some light on this?

https://github.com/ionic-team/cordova-plugin-wkwebview-engine/issues/125

darkyen commented 6 years ago

When using iOSes UIWebView there is no access control restrictions placed on the browser, for security reasons Apple's WkWebView forces CORS. When making a call to oauth/token endpoint we enforce CORS so that no malicious website can exchange the token or call Auth0's API Servers from a Webpage which is not explicitly allowed.

You can add http://localhost:8080 in the list of allowed origin in the dashboard but we strongly recommend doing against that, because doing so will make your application insecure.

For now I recommend using the base web view until we / ionic have a better solution for this.

gdjennings commented 6 years ago

@darkyen Any ETA on this. Auth0 in wkwebview has been a non-starter for months now. While poking around, I found this. https://medium.com/posts-from-emmerge/implementing-an-oauth2-login-flow-in-wkwebview-de74e23fe9ee

darkyen commented 6 years ago

We already do what the blog post suggests using the plugin. The problem is that we can't trust http://localhost:8080 as a trusted entity. Allowing that will also allow any applications running http://localhost:8080 will be allowed to access Auth0's API from any platform thus making your app insecure.

timbru31 commented 6 years ago

Is there any solution yet? Even with localhost:8080 allowed for CORS it's showing the spinner and not closing the view.

parkbroom commented 6 years ago

wkwebview is the new standard. there should be a way around this imo

simonwatt commented 6 years ago

Not having WKWebView support really is an issue and makes me very hesitant to use this library. Even Apple documentation says to use WKWebView in apps running iOS 8+.

gdjennings commented 6 years ago

I spent a bit of time last night trying to identify the source of this bug so that I can either work around it or get it fixed. Unfortunately, I have hit a bit of a dead end. It seems that when you open the SFSafariViewController from a wkwebview enabled app, the custom url scheme doesn't get sent back to the app. No amount of whitelisting or csp makes a difference to this behaviour. Someone mentioned it might be because iOS thinks the app is already active so doesn't reactivate it. I keep thinking there is some magic setting, option or parameter needed to just unblock the custom-url-scheme callback but i just cant find anything. Interestingly, if you click the little safari icon in the sfviewcontroller so that it opens the auth in a safari window, the callback activates correctly giving weight to the "don't activate an already active app" theory.

Worth mentioning also is that this only seems to happen on an actual device (and always happens). In simulator, it works as expected.

Does someone have a working version of wkwebview + auth0-cordova? It could possibly be a result of some dirty config from adding and removing platforms and plugins many times over? If not, how can we get the SFSafariViewController to trigger the handleOpenURL when the host is a wkwebview app?

gdjennings commented 6 years ago

It looks like cordova-plugin-customurlscheme doesn't implement the necessary native functions to receive url events while the app is in the foreground. ionic-native/deeplinks plugin receives the callback but I still haven't got it to work seamlessly on device yet.

gdjennings commented 6 years ago

Callback not being processed because wkwebview pauses javascript when sfsafariviewcontroller is in foreground. Ionic Deeplinks plugin logs the native event but the javascript is not executed on device.

gdjennings commented 6 years ago

It works! If you add cordova-plugin-background-mode. Specifically this fork. No need to enable background-mode in JS, wkwebview processes the url handler just with the plugin present. My specific working config uses that fork of background-mode and ionic-deeplinks-plugin rather than cordova-plugin-customurlscheme.

MT-- commented 6 years ago

@gdjennings great find! thank you!

ewhauser commented 6 years ago

@gdjennings - Would you be willing to share an example of what this looked like on the JS side with the ionic-deeplinks-plugin? I have this working on Android using SafariViewController and I'm trying to get it working on iOS.

gdjennings commented 6 years ago
import { Component, NgZone, ViewChild } from '@angular/core';
import { Platform, NavController, App } from 'ionic-angular';
import { StatusBar, Splashscreen } from 'ionic-native';
import { Deeplinks } from '@ionic-native/deeplinks';

import { TabsPage } from '../pages/tabs/tabs';
import { AuthorisationService } from "../services/authorisation.service";

import Auth0Cordova from '@auth0/cordova';

declare var ga:any;

@Component({
    template: `<ion-nav #rootNav></ion-nav>`
})
export class MyApp {
    @ViewChild('rootNav') nav: NavController;

    constructor(platform: Platform, 
        private auth: AuthorisationService,
        private zone: NgZone,
        private deeplinks:Deeplinks,
        private app: App) {

        platform.ready().then(() => {
            // Okay, so the platform is ready and our plugins are available.
            // Here you can do any higher level native things you might need.
            StatusBar.styleDefault();
            Splashscreen.hide();
            this.app.viewWillEnter.subscribe(viewCtrl => ga('send','screenview', {'screenName': viewCtrl.name}));

            if (window["cordova"] && window["cordova"].platformId !== 'browser') {

                this.deeplinks.route({
                }).subscribe((match) => {
                    Auth0Cordova.onRedirectUri(match.$link.url);
                }, (nomatch) => {
                    Auth0Cordova.onRedirectUri(nomatch.$link.url);
                });
            }

            // This function is part of "Set Up Auth0-Cordova"
            // (<any>window).handleOpenURL = (url) => {
            //  Auth0Cordova.onRedirectUri(url);
            // };
            this.auth.token
            .subscribe(() => {
                this.zone.run(() => {
                    this.nav.setRoot(TabsPage);
                });
            });

        });
    }

}
darkyen commented 6 years ago

@gdjennings Hey grant, thanks a lot for all the work you have put into this, I'm looking at cordova plugin background mode atm. What you suggested does seem very appealing to use for WkWebView. Additionally, was this only affecting custom uri or universal links only? I have had issues with universal links in the past, but universal links will only get activated if the callback domain is different, and therefore when you click on safari button it works.

gdjennings commented 6 years ago

@darkyen I was only trying to solve the token callback since that was blocking me. The deeplinks plugin just gave me the feedback I needed to figure out where the problem was. The root of the problem seems to be the js process of wkwebview get's paused while sfsafariview is focussed. I am not sure if there would be any difference if it was a universal link or custom uri since it will still get directed to the app with a paused js process (and you can't dismiss the safari view from the inside).

I'm not an ios native dev so my solution is probably a bit crude. I imagine if you dismissed the sfsafariview from native code, you could deliver the link back to the wkwebview thread without needing the background-mode plugin. I think this plugin should do that itself, since background-mode is a bit of a sledge-hammer and the effect on battery life might need some testing.

From a documentation point of view, it might be worth adding that if using wkwebview, you will need background-mode, at least until there is an alternative solution.

The whole ios environment for hybrid is pretty ^&%#ed. As you know, with wkwebview, you can't secure the origin...so to solve this, auth0 would need to build a comprehensive plugin that also does API calls with a proper (e.g custom url scheme) origin in the header.

At least I have an app that works now (and got approved) and I didn't have to rip out the auth code.

saschwarz commented 6 years ago

This week Ionic announced "WKWebView will soon be the default for all Ionic apps running on iOS, before the release of the iPhone X." http://blog.ionic.io/ios-11-checklist/

Now that Ionic recommends Auth0 as an authentication solution I'm hoping you can work with them to get this resolved.

mlynch commented 6 years ago

(Max from Ionic here), we're looking into what we can do on our end and reached out to Auth0 to make sure this works 🤖

simonwatt commented 6 years ago

At a glance it looks like cordova-plugin-background-mode is likely to cause App Store rejections, and have a few other consequences (e.g draining battery usage), from the plugin documentation it says:

"Store Compliance Infinite background tasks are not official supported on most mobile operation systems and thus not compliant with public store vendors. A successful submssion isn't garanteed."

Therefore I'm not sure if it seems like a viable solution for me if the App is going in the App Store. If I only enable background mode just before launching the auth0-cordova dialog (on my App this is triggered by Login/Register buttons), and disable it once the callback is hit then I'm hoping this wouldn't be a problem, but I don't want to get to the submission stage and then find out it's a problem if all my testing is already done with WKWebView.

gdjennings commented 6 years ago

@simonwatt Just the existence of the background-mode plugin was enough to change the background behaviour of wkwebview (in iOS 10...haven't tried 11, might have changed), so it didn't need to be enabled and disabled. Not sure why. My app got approved, but apple approval is a bit of a moving target, so YMMV. My users haven't been complaining about battery life, so I think it might be ok (without really understanding it 😕 ).

One way or another, this plugin needs to dismiss the SafariView from native code on iOS when using WkWebView. Not sure what the best way or who is going to do that, but until that happens, the only way auth0-cordova and WkWebView are going to play nice together is background-mode.

brassier commented 6 years ago

Any more progress on this? Looks like ionic's announcement is making this a bigger deal.

http://blog.ionic.io/wkwebview-for-all-a-new-webview-for-ionic/

simonwatt commented 6 years ago

Unfortunately I can't even use the cordova-plugin-background-mode work around, as there is currently an issue on that particular plugin where it is crashing if WKWebView is being used. https://github.com/katzer/cordova-plugin-background-mode/issues/317 (same issue is happening for me on a PhoneGap app).

brassier commented 6 years ago

@mlynch - Can you weigh in on if there's been any progress working with Auth0 on this? This ticket has gone cold, yet Ionic has been pushing forward with WkWebView.

aaguiarz commented 6 years ago

Hi,

We are in conversations with Ionic for a way to handle this. I can't promise much yet.

Regards,

Andres Aguiar Product Owner, Auth0.

enea-tsanai commented 6 years ago

Hi,

I am using Ionic 1 with WKWebView and auth0-cordova works for me in iOS 9+ without adding any plugins (e.g. cordova-plugin-background-mode). I had to move the agent.close() before the client.oauthToken(...) in index.js like this:

agent.close();
client.oauthToken({
    code_verifier: verifier,
    grantType: 'authorization_code',
    redirectUri: redirectUri,
    code: code
}, function (exchangeError, exchangeResult) {
    if (exchangeError) {
        return callback(exchangeError);
    }
    return callback(null, exchangeResult);
});

I also had to add http://localhost:8080 in the Allowed Origins (CORS) section of my client settings in the Auth0 dashboard. Can someone confirm if http://localhost:8080 is a secure setting? Is there any better alternative for the CORS issue when using the WKWebView?

Thank you in advance!!!

simonwatt commented 6 years ago

@aaguiarz It would be good if any solution to this isn't Ionic specific, as it's also happening on regular PhoneGap Apps that aren't using Ionic.

osikes commented 6 years ago

Ran into issue as well, I found my own hacky solution by...

  1. Correctly adding http://localhost:8080 to my auth0 allowed origins.
  2. Installing cordova-plugin-background-mode and then correcting the variable as noted in this issue, https://github.com/katzer/cordova-plugin-background-mode/issues/317 ... not great but works.
ghenry22 commented 6 years ago

You can try my fork of the background mode plugin. It has some changes.

1) the base background mode plugin aims to keep the app alive FOREVER by continuously looping a silent audio file in the background and relying on background audio capability to support this.

My fork removes the audio file playing and just stops wkwebview from instantly suspending when a running app is sent to the background. It will still be suspended after the usual amount of idle time in the background as per the OS, so it doesn't drain battery and it doesn't do anything that would cause app store rejections.

2) fixed the bug with the deprecated variable that was stopping the background mode plugin from working with wkwebview.

https://github.com/ghenry22/cordova-plugin-background-mode

tahmina8765 commented 6 years ago

@ghenry22 - what I need to do after adding this background-mode plugin in JS side? Would you please share some example JS code?

ghenry22 commented 6 years ago

The background mode plugin just allows wkwebview to keep running in the background. Just install the plugin and call it's enable function to enable background mode. Then you can run whatever javascript you would normally run.

tahmina8765 commented 6 years ago

@ghenry22 - Thanks for fixing the issue in background-mode plugin. I have just installed your plugin by running -

ionic cordova plugin add https://github.com/ghenry22/cordova-plugin-background-mode.git

Then the auth0-sample for ionic2+ has started working in iPhone. I can not understand how it has been enabled, or from where it has been enabled.

gdjennings commented 6 years ago

This plugin really needs to handle the urlscheme callback in native part and dismiss safariview rather than rely on bg mode for ios.

On 8 Nov. 2017 3:17 pm, "Tahmina Khatoon" notifications@github.com wrote:

@ghenry22 https://github.com/ghenry22 - Thanks for fixing the issue in background-mode plugin. I have just installed your plugin by running -

ionic cordova plugin add https://github.com/ghenry22/ cordova-plugin-background-mode.git

Then the auth0-sample for ionic2+ has started working in iPhone. I can to understand how it has been enabled, or from where it has been enabled.

— You are receiving this because you were mentioned. Reply to this email directly, view it on GitHub https://github.com/auth0/auth0-cordova/issues/42#issuecomment-342713483, or mute the thread https://github.com/notifications/unsubscribe-auth/AHu3iUokgm_o_flCqppsuhWewiFR9E5Fks5s0Tl-gaJpZM4NqpLi .

darkyen commented 6 years ago

I have had problems in the past with calling cordova apis in custom-uri-scheme callbacks. Ideally the execution should happen after the callback, however this delay causes the application to go into frozen when running with WKWebView. I am currently working on handling both use-cases.

ghenry22 commented 6 years ago

@gdjennings I don't disagree, my modified background mode plugin just makes wkwebview work like uiwebview when the application is running but in the background so at least it removes that inconsistency and makes life a bit more predictable, not just for auth0 but for basically any hybrid app that wants to do anything in the back ground.

The original background mode plugin spoofed audio playback to keep the app alive forever which is not the behaviour that most people actually need here so it wasn't ideal.

gdjennings commented 6 years ago

@ghenry22 Nice. The whole ionic -> auth0 -> cordova -> safariview thing is so clunky I'm ready to chuck it in the bin. I just dread needing to do an update. I expect any minor change is going to bring the house of cards crumbling down. The app runs better in safari. Pity apple doesn't let you publish web sites thru the app store.

brassier commented 6 years ago

Can anyone from Auth0 confirm if @enea-tsanai 's solution is something worthy of pulling in? @aaguiarz ?

darkyen commented 6 years ago

@brassier, I am already working on porting @enea-tsanai's solution to a safer manner (it might crash the app in non WKWebView)

brassier commented 6 years ago

@darkyen - That's great news. Looking forward to using Auth0 Cordova + WKWebView. Thanks!

darkyen commented 6 years ago

@brassier I just pushed changes that adds @enea-tsanai logic, I have however faced some issues with CORS on WKWebView (the Ionic one) even when CORS is explicitly added on the Auth0 tenant. I'll get back on this when I find out what exactly is going on