Closed gary-archer closed 6 years ago
Local loop back interfaces work well for your use case. They are easy to manage and consistent from a programmatic perspective. You also only need it to run for a small window of time. So I would recommend that.
Thanks for the answer - though there are still some challenges here.
RELIABLE + POLISHED DESKTOP LOGIN USER EXPERIENCE These aspects are not really covered in any online sample or article - Login UX is something that business owners at my company (and many others) will care a a lot about.
ALLOWING THE USER TO RETRY This is awkward at best to implement using the loopback interface:
GITHUB DESKTOP
BROWSER PAGE AFTER LOGIN
I'M LEANING TOWARDS CUSTOM URL SCHEMES
As always, coding is the easy part - getting past blocking issues is what concerns me. I will post back once I feel we've got things as good as we can - hopefully the lessons learned will be useful to others also.
Your analysis looks quite accurate to me. A few comments:
I want to use PKCE handling so that the security is right
PKCE can be added to any OAuth flow (and it's pretty simple), so this won't impact what user-agent you use for the authorization, or the type of redirect URI you select. You should use PKCE on all OAuth authorization flows, especially public (native app) clients.
We'd like to avoid relying on our customer IT policy allowing the loopback listener
I've never heard of a environment that can't open a port on the loopback interface, but I guess one may exist. As I write in RFC 8252, you should use the loopback IP literal, rather than the "localhost" domain. This avoids configuration issues with local domain resolution of "localhost" and generally results in a port that's binded to the loopback interface (you should verify this, and ensure you are binding only to the loopback, meaning it won't accept LAN connections).
I tested the default firewalls on Mac & Windows, both require confirmation from the user if you bind to all network interfaces, but NOT if you bind only to loopback (which is good).
Why would someone set policy to block loopback TCP/IP connections? What would that achieve?
The desktop app gets no notification if the user closes the browser tab
True. So the app should still show the "Sign in" button. If the user returns to the app and taps it again, you can discard the previous session and start a new one.
BROWSER PAGE AFTER LOGIN
This is where loopback may have an advantage. With the loopback redirect, the native app can render a web page which includes a meta-refresh to redirect the user-agent to the page of their choice (e.g. a page displaying instructions like "return to the app").
For custom-URI schemes, if you do a simple redirect to a custom URI scheme, the page will likely be blank (as there is nothing to render). One hack you can try is to do the custom URI scheme loading in a javascript call. This isn't quite as reliable in my experience as doing the redirect.
An advantage in custom URI schemes is that typically the app is launched in the foreground which is desirable.
On my Windows PC this registers a custom URI scheme
Here's a recent sample showing this in a traditional Windows app: https://github.com/IdentityModel/IdentityModel.OidcClient.Samples/tree/master/WindowsConsoleSystemBrowser
For UWP windows apps these samples demo custom URI schemes: https://github.com/googlesamples/oauth-apps-for-windows/tree/master/OAuthUniversalApp
I'M LEANING TOWARDS CUSTOM URL SCHEMES
I think this is very reasonable for Desktop. To me, both custom URI schemes and loopback are viable, and you should pick what works best for your particular deployment environment.
Having implemented a simple HTTP server for loopback redirects on Mac and Windows I don't think it's that much more complex from an implementation point of view, I think it more comes down to your deployment environment and UX preferences.
While there are a lot of corner cases to get right with the browser auth flow, there are some benefits to the user experience too. Of course, security is a big reason to go to the browser, but there are other benefits like SSO, integration with browser password managers (if used), and support for advanced second factor (e.g. U2F).
Here's a recent sample showing this in a traditional Windows app: https://github.com/IdentityModel/IdentityModel.OidcClient.Samples/tree/master/WindowsConsoleSystemBrowser
As the author of this sample, I can speak from experience that a custom URI scheme on your host OS just tends to work better than having the client listen on the loopback device. No admin related issues, and the window focus/z-order is better.
@brockallen have you encountered administrator issues with loopback in the wild? Did they have good reasons, or was it collateral damage from an over-broad policy (not that this changes the calculation much for app developers)? I've not seen this myself, so am keen to hear of any cases.
I've not really run into any issues personally, but I sometimes hear of the odd question about the firewall settings. I guess it depends on the environment. But with the custom URI scheme (especially when just the user's local registry is all that needs the config -- so no admin config required) it seems like fewer moving parts to make the callback work.
Interesting. Then I'll continue my claim of no confirmed issues in the wild for loopback.
During my research into "does anyone block loopback" I found some discussions which mostly centered around the fact it would be crazy to do this, and that a lot of things may unexpectedly break (particularly in the case of Linux, but true for all platforms).
Given loopback is strictly a local channel I can't think of any theoretical reasons why an admin would block it either.
We have a cross-platform sample of the loopback approach as well (using asp.net core): https://github.com/IdentityModel/IdentityModel.OidcClient.Samples/tree/master/NetCoreConsoleClient
Thanks guys - great to get this feedback from high calibre people. Looks to me like both Loopback and Private URI schemes are viable options.
Feel free to close this issue. Out of interest I've implemented both flows in Electron and my company will choose the one they prefer.
I'll also post a couple of little issues I've worked around with the AppAuth-JS library. Hope I can help you improve the library further - my company used AppAuth-iOS / Android and they worked very well for us.
Nice library guys - my company provides some desktop apps for investment banks. I was hoping you could confirm that I am following the recommended direction below.
LOGINS SHOULD NOT USE WEB VIEWS This seemed to be the standard technique a few years ago, using callback URLs such as urn:ietf:wg:oauth:2.0:oob, but this is no longer considered to be good security. Also, Single Sign On and Password Autofill won't work on a web view.
LOGINS SHOULD USE THE SYSTEM BROWSER This Auth0 Link summarizes the issue - logins must use the desktop browser to be considered good security.
OPTIONS The OAuth Standards for Native Apps mentions 3 redirect options:
OPTION 1 - Private URI Scheme (com.mycompany.com:/mydesktopapp)
I could not use this scheme for my Electron app - the System browser will refuse to redirect to a URL of this form.
OPTION 2 - Claimed HTTPS Scheme (https:/mycompany.com/myapp)
I think this also requires special operating system support - I cannot use it for my Electron app.
OPTION 3 - Loopback Interface (http://127.0.0.1:8000) The AppAuth Electron sample uses this option:
It looks like the only good option for desktop logins.
PLANNING DEPLOYMENT We need to tell IT staff at investment banks to not block the local web server. If we ever ran into an IT department who refused to allow it, the only backup option we could offer would be to login on a web view.