jbreckmckye / electron-auth0-login

Helper widget for Auth0 authentication in Electron desktop apps
MIT License
27 stars 19 forks source link

Google rejects logins made via "webviews" #35

Open timfish opened 2 years ago

timfish commented 2 years ago

Google regularly reject logins made in a BrowserWindow. I have MFA enabled on my Google account and it just doesn't allow it: https://support.google.com/accounts/thread/22873505?hl=en

The recommended way to do this is to open the Auth0 login URL in the users default browser via shell.openExternal(url). This also has the added bonus that users are almost certainly already logged in with any auth providers so no need to do login+MFA again.

For this to work, you need to host a static page that Auth0 redirects to after login. This page needs to have user instructions and JavaScript which returns the token to the app. There are few different ways to do this.

Localhost Websocket

I noticed Discord and a few others doing this. Your app exposes a websocket on localhost and any website, even one in a secure context can send it the token via the websocket. I haven't looked too deeply into this because it's complicated and it feels like opening a websockets to every website has security implications that I don't fully understand...

Protocol Handler

You're Electron app can register my-app:// protocol and you can redirect to that URL and the browser will pass the full URL to your app.

I've got an app that does this but it has a number of downsides:

Clipboard

Courtesy of Ani Betts: https://twitter.com/anaisbetts/status/1470879935552237574

  1. Desktop app opens Auth0 URL in browser
  2. Desktop app saves a copy of the clipboard
  3. Browser does sign-in, gets a token
  4. Browser saves the token in the clipboard, instructs user to go back to desktop app
  5. Desktop app is waiting on window focus, when it gets it, it reads the clipboard
  6. Restore old clipboard contents
jbreckmckye commented 2 years ago

It's pretty late in the evening here, way past midnight. This is a very dense report which covers quite a few things.

Let me first clarify what the actual problem is

  1. You want to use Auth0 with Google as an SSO provider
  2. You want to sign in on Electron (which is where this library comes in)
  3. This library uses an Electron browser window, which Google doesn't like as it doesn't trust embedded windows

This is an interesting one. I can see a few benefits to moving users to their default browser:

  1. They can see and verify the URL and certificates
  2. They can use their password managers or existing credentials

On the other hand, if we don't (e.g. by using a user agent workaround), we are in this situation:

  1. The token exchange itself should still be fine, it's more Google's trust of us that's the issue
  2. Whilst a casual user of the library won't have access to the browser window, it's very feasible to write a malicious electron app that attempts to spy on the challenge page. So Google will want to stop any workarounds eventually
  3. There's a social argument that it's better to train users to only do auth / 2FA through their browsers, always checking hosts, always checking certificates

The problem with changing the implementation is this:

For this to work, you need to host a static page that Auth0 redirects to after login. This page needs to have user instructions and JavaScript which returns the token to the app. There are few different ways to do this.

If I understand the ask correctly, that significantly increases friction for anyone implementing this flow. It also means anyone wanting to build an authenticated desktop app presumably has to deploy a web server as well to support this.

Now, the way this library works is based on a set of 'operations' and 'adapters', with the latter being swappable modules providing IO. One of those IO duties is the challenge flow and another is the verifier flow.

So it may be possible to support both approaches, with one set of adapters doing the browser window / clipboard sniffing trick, a la Slack. And then, if necessary, either deprecating the embedded flow over time, or making it non-default.

timfish commented 2 years ago

Let me first clarify what the actual problem is

That's a great summary of my babbling!

I was lucky in that I discovered this with my own account while testing BrowserWindow but I know others who've shipped apps to later find out a reasonable chunk of Google users couldn't log in.

that significantly increases friction for anyone implementing this flow. It also means anyone wanting to build an authenticated desktop app presumably has to deploy a web server as well to support this.

I currently do this with a single statically hosted HTML file so no server required.

We could add a similar HTML file to this repository/npm package and default to redirecting to an unpkg CDN URL. It would effectively be hosting the HTML file for free and if versioned URLs are used, the file contents can be trusted to not change. The only friction for users at that point would be adding the unpkg URL to the allowed redirect URLs in the Auth0 settings.

I'm pretty sure we can pass additional data through Auth0 authentication to the post login redirect page. This could be used to enhance the instructions like including the name of the app you should go back to.

Users could host the file themselves and override the URL in settings if they want to.

the way this library works is based on a set of 'operations' and 'adapters'

That may well be an easy way to test it!

AriVagelatos-KSO commented 2 years ago

@timfish would it be possible to share your static HTML file source code?

I don't think auth0 needs to redirect to the static html page based on the documentation when you tell auth0 you want to create an ionic / capacitor application. Auth0 seems to be able to redirect directly to a deeplinked url . I dont have a link to the tutorial because it is shown after logging in and going to the app, but this is the github repo https://github.com/auth0-samples/auth0-ionic-samples/tree/main/angular . The Auth0 quickstart for ionic/capacitor discusses redirecting to ios/android deeplinks and this tutorial discusses setting up deeplinking in electron: https://www.electronjs.org/docs/latest/tutorial/launch-app-from-url-in-another-app