microsoft / WindowsAppSDK

The Windows App SDK empowers all Windows desktop apps with modern Windows UI, APIs, and platform features, including back-compat support, shipped via NuGet.
https://docs.microsoft.com/windows/apps/windows-app-sdk/
MIT License
3.84k stars 320 forks source link

WebAuthenticationBroker API that supports all WinAppSDK OS's and application types #441

Open BenJKuhn opened 3 years ago

BenJKuhn commented 3 years ago

Proposal: Lifted WebAuthenticationBroker API that supports all Reunion OS's and application types

See #398, #366 - This issue is similar, but distinct in that it covers creating a new, lifted API, rather than updating the existing one to work for more application types.

Summary

Create an API that developers can use in any application type to implement OAuth2 functionality in any app supported by Reunion.

Rationale

The existing OS API that provides this functionality requires a core Window, which, for practical purposes, means that it only works for UWP-style application, and can't be used in other types of applications. Even if the OS API were updated, it would likely only be updated for new OS versions. It would be helpful for developers to have consistent support across OS versions.

https://task.ms/31649739

mrlacey commented 3 years ago

And, of course, this should build on top of WebView2!

Note. The UWP one is based on IE and because of this will not work with many websites, forcing the developer to not be able to use WAB for Oauth with those sites.

michael-hawker commented 3 years ago

This was originally a request on the WebView2 team here: https://github.com/MicrosoftEdge/WebView2Feedback/issues/171

There's probably some interop involved I believe between Edge, the OS, and WebView2?

dotMorten commented 2 years ago

And, of course, this should build on top of WebView2!

I disagree. I'd rather we use the user's default browser to log in, then use protocol activation to come back to the application, as it follows better practices, and is impossible to spoof, and also has the benefit of supporting any saved credentials the user might have in their browser. I managed to actually make this work, but it was a lot of work, lots of code, manifest changes for protocol activation, dealing with app activation args, finding the right instance, shutting down the app if it was the wrong instance, redirecting to the correct instance, then dealing with resuming the authentication workflow there. It was quite non-trivial, and I really wish this could be wayyyyyyyyyyy easier. I wish there was just a single call I could make that would do all this for me. Something like public static Task<Uri> OAuthSignIn(Uri authorizationUri, Uri callbackUri); and protocol activation, app instance tracking and resuming etc is just magically handled for me. I shouldn't have to configure my app at all, just configure my oauth with the right callback uri, and then pass it in here.

Another reason to not require webview2: There's no guarantee webview2 is actually available to the user.

jonwis commented 2 years ago

app instance tracking and resuming etc is just magically handled for me. I shouldn't have to configure my app at all, just configure my oauth with the right callback uri, and then pass it in here

I agree with everything you've got here - it's important to use the same browser as the user is used to because it may have SSO cookies already set up making the auth basically no-op, or the user might have a password manager associated with it (Edge, LastPass, etc.) where they store their cookies.

For reference, there is https://github.com/Microsoft/cpprestsdk/blob/master/Release/src/http/oauth/oauth2.cpp (and its friend https://github.com/Microsoft/cpprestsdk/blob/master/Release/include/cpprest/oauth2.h), which we'd have to review to see if it behaves correctly. VSCode already does this as well, setting itself up a temporary HTTP server to support the redirect, etc.

dotMorten commented 2 years ago

Clever trick with the temporary http server. Very clever actually. There are some challenges though with available ports, and what ports you get to configure in the oauth redirect configuration

bgavrilMS commented 2 years ago

If you need a reference implementation, please feel free to use MSAL's, it is MIT licensed.

WebView2 WebView1 System Browser using http listner

The discussion around embedded vs system browser is long and inconclusive. When it comes to Azure Active Directory, we've concluded that on desktop it's better to use a broker (WAM on Windows) because brokers increase security and SSO. Internally the broker uses an embedded browser.

Many apps use browsers today and generally the embedded browser are preferred because they provide a better user experience. System browsers are cross-plat but the experience is worse. I have not yet seen any conclusive evidence that system browser is better or worse than embedded browser in terms of security. In terms of SSO, embedded browsers fare poorer, because you are likely to have SSO cookies in your system browser already. But once you start using the embedded browser, it should store the cookies as well.

Hope this helps.

dotMorten commented 2 years ago

Until the WinAppSDK adds this, I've added this ability to WinUIEx v1.4. It's nothing more than a simple one-line call. See https://dotmorten.github.io/WinUIEx/concepts/WebAuthenticator.html

mattleibow commented 2 years ago

The solution by @dotMorten works well if you are controlling the app, but not so much as a library - and especially as maui which is a framework that libraries will be based on.

The issue is that the auth callback starts a new process - which may be unexpected for the app, and then it also modifies app state unexpectedly (that may override user data or be overridden by user data): https://github.com/dotMorten/WinUIEx/blob/main/src/WinUIEx/WebAuthenticator.cs#L108

The killing of the new process may also be unexpected for the app: https://github.com/dotMorten/WinUIEx/blob/main/src/WinUIEx/WebAuthenticator.cs#L100

Not sure what the best solution is, but having this in a popup that is controlled by wasdk is more contained and does not require any new processes.

This pop out to a browser works on Android/iOS because even though a "new window" happens, it is the same process and can be intercepted in known places. iOS has a special place, and Android can have a special activity designed for handling callbacks.

Windows on the other hand launches a brand new app.

I appreciate that popping out to the browser is a "better" scenario from the user's credential perspective and default browser, but this is not super windows-friendly. The callback triggers a new proc, which is killed and even if there was a way to share data, Windows doesn't have a place to decide where a new app should be launched or not.

dotMorten commented 2 years ago

it also modifies app state unexpectedly

Note: This only happens if the user didn't already set that state.

Personally I'd like to see something that's a combo of a popup and using the default browser - ie some way a browser knows the request is coming from a specific app and knows to direct you back to that specific app instance and close that tab gain, instead of asking the user to open the app again from the browser - ie overall more akin to what iOS and Android does.

VR-Architect commented 2 years ago

Any movement or guidance on starting new Maui/WebAPI/BlazorServer combined solution? Is a solution soon?

I am following this Microsoft tutorial but says Windows not working yet.

https://docs.microsoft.com/en-us/dotnet/maui/platform-integration/communication/authentication?tabs=windows

VR-Architect commented 2 years ago

Will there be a way to leverage the ASP. NET CORE API server as the backend server? All of my various clients, including Blazor Server, already go through the API for DB access. If yes, any chance someone could make a tutorial for this solution setup?

Our goal is 100% of business logic and per-method authorization is contained in the API so our customers could build their own clients if they choose as we are a SaaS provider.

hansmbakker commented 1 year ago

@BenJKuhn is there any update to this? I see @mattleibow added maui-7.x and Maui 7.0 went GA - is there any roadmap or expected moment we can use this? Given that the majority of the apps (gut feeling, admittedly) need some form of authentication nowadays, I find it surprising to see that this was not escalated further in Microsoft or made a blocker before going GA... - and this does not only hit MAUI apps but all WindowsAppSDK apps as I understand cc @ujjwalchadha @jonwis @angelazhangmsft

sb34000 commented 1 year ago

Any update ?

Quaybe commented 1 year ago

Please?

MatthewBacon-Neteo commented 1 year ago

The fact that this has taken so long to get any traction is incredible.

Authentication for cross platform MAUI apps is dependent on this functionality and people are literally having to beg for updates.

MUN1Z commented 1 year ago

Any updates?

kfrancis commented 1 year ago

Any updates?

Murtaya commented 1 year ago

Any update? We're evaluating using MAUI and....well, are kinda blocked on this and surprised at the lack of responses...

matt-goldman commented 1 year ago

A better option is to use WinUIEx as mentioned earlier in this thread

emillium commented 1 year ago

I have actually moved completely away from the Microsoft stack because of this.

AviNessimian commented 1 year ago

Any update ?

MatthewBacon-Neteo commented 1 year ago

A better option is to use WinUIEx as mentioned earlier in this thread

Except it isnt.

As reported when the site calls back to the app: "Windows on the other hand launches a brand new app."

It might be a work around for android / ios but doesnt work for Windows apps.

Maui is supposed to be cross platform and depends on this functionality.

MatthewBacon-Neteo commented 1 year ago

@BenJKuhn sorry to at you but is there any progress or words of wisdom with how we can prioritise?

This is a real put off for many wanting to use Maui for cross platform apps.

ronanj2 commented 1 year ago

I see a lot of people in this thread looking for updates ... and NOBODY getting back with any. What is going on?

nterreaux commented 1 year ago

I'd like to try the solution with WinUIEx, but I'm using .net 7 and it doesn't seem to be compatible. Is there a solution?

dotMorten commented 1 year ago

@nterreaux .net 7 is fully supported by WinUIEx

nterreaux commented 1 year ago

Ok thanks @dotMorten, I'm relatively new to .NET. The WinUIEx package requires at least version 1.3.230502000 of Microsoft.WindowsAppSDK. However, I can't update it. It says that other versions are "blocked by the project". I'll see if I can do something, as I currently have version 1.2.221209.1.

dotMorten commented 1 year ago

Yes you’ll need to reference 1.3 in any project that uses WinUIEx or depends on a project that uses WinUIEx.

nterreaux commented 1 year ago

I'm now using WinUIEx for my OAuth 2 authentication. Everything works perfectly except for the fact that the user's default browser page doesn't close automatically. This isn't extremely annoying, but is there a solution for closing the browser after authentication?

dotMorten commented 1 year ago

@nterreaux since this thread is going more and more off topic let’s try and keep the winuiex questions over in the WinUIEx repo

ransagy commented 1 year ago

More because we have zero response from any maintainer, tagged or otherwise, on the gameplan of a core feature of a core platform in this cross-platform framework solution.

Anytime now, MS employees..

MatthewBacon-Neteo commented 1 year ago

@ransagy Agree the lack of response hinders any confidence in the framework and Maui. Sad to say that my team / project have had to abandon in favor of other stacks.

andreasbrostencab commented 1 year ago

I am also very interested in any status info around this.

Azizxon commented 1 year ago

Any updates?

Hantse commented 1 year ago

It's a basic usage in app, very important, some feedback ? Should be great if dev team focus on fix this.

dotMorten commented 1 year ago

Heads up: Google's OAuth is going to start blocking embedded webviews for OAuth: https://developers.google.com/identity/protocols/oauth2/policies#browsers I can imagine other providers will start requiring similar things. This makes it even more important to provide an out of the box secure way to sign in with OAuth, since many are currently just falling back to an embedded WebView2.

FedericoSMEC commented 1 year ago

A better option is to use WinUIEx as mentioned earlier in this thread

Except it isnt.

As reported when the site calls back to the app: "Windows on the other hand launches a brand new app."

It might be a work around for android / ios but doesnt work for Windows apps.

Maui is supposed to be cross platform and depends on this functionality.

@MatthewBacon-Neteo A bit late to the party here. I managed to use a workaround for windows that might help you.

When the second instance of the app is initializing (before the window of the second instance is created), I extract the auth code from my custom uri (e.g. mycustomuri://authorization?authCode=abc), I then use Named Pipes to send this code to the first instance of the app (the one that is waiting for the code) and then kill the second instance.

It is quite a workaround but on Windows it works fine and the second app is not seen by the user. Of course, fixing this issue would make everything easier.

dotMorten commented 1 year ago

You don't have to use your own named pipes to redirect. There's an actual API for that (RedirectActivationToAsync). See https://learn.microsoft.com/en-us/windows/apps/windows-app-sdk/applifecycle/applifecycle-instancing#redirection-logic-based-on-activation-kind

FedericoSMEC commented 1 year ago

Thanks @dotMorten. I don't want to derail the conversation, although I fail to see how I can use that RedirectActivationToAsync in my .net maui app.

IlGalvo commented 1 year ago

I think I found a workaround after many tries:

var redirectUrl = "http://127.0.0.1:{0}/authorize/"; // or "http://localhost:{0}/authorize/"

var tcplistener = new TcpListener(IPAddress.Loopback, 0);
tcplistener.Start();

var port = ((IPEndPoint)tcplistener.LocalEndpoint).Port;
tcplistener.Stop();

redirectUrl = string.Format(redirectUrl, port);

using var httpListener = new HttpListener();
httpListener.Prefixes.Add(redirectUrl);
httpListener.Start();

var oAuth2Url = "your-oauth2-url"; // make sure (if present) redirect_url = redirectUrl
Process.Start(new ProcessStartInfo("cmd", $"/c start \"\" \"{oAuth2Url}\"") { CreateNoWindow = true });

var context = await httpListener.GetContextAsync();

var html = @"<html><head><title>OAuth 2.0 Authentication Token Received</title></head><body> Received verification code. You may now close this window.</body></html>";
var bytes = Encoding.UTF8.GetBytes(html);

context.Response.ContentLength64 = bytes.Length;
context.Response.SendChunked = false;
context.Response.KeepAlive = false;
var output = context.Response.OutputStream;
await output.WriteAsync(bytes);
await output.FlushAsync();
output.Close();
context.Response.Close();

var result = context.Request.QueryString; // contains url result params (eg: code etc)

The only encountered problem is: if you close the browser before user-auth-flow completes, var context = await httpListener.GetContextAsync(); hangs indefinitely.

elijahmontenegro commented 1 year ago

Has anybody found a workaround for use in MAUI windows apps? I would appreciate if you can share any insight on this! Really frustrating!

illja96 commented 1 year ago

@FedericoSMEC can you post your code for a workaround, please?

lcarrion2406 commented 1 year ago

Any update?

dotMorten commented 1 year ago

Has anybody found a workaround for use in MAUI windows app

@elijahmontenegro Yes: https://dotmorten.github.io/WinUIEx/concepts/Maui.html#use-winuiexs-webauthenticator-instead-of-net-mauis

ataparia commented 1 year ago

ue is that the auth callback starts a new process - which may be unexpected for the app, and then it also modifies app state unexpectedly (that may override user data or be overridden by user data):

Hi @dotMorten , I tried to reference WinUIEx.WebAuthenticator in the App.xaml.cs but I don't see CheckOAuthRedirectionActivation() method on there. I am using the 1.5 version of WinUIEx package.

Am I missing something?

dotMorten commented 1 year ago

@ataparia Let's do this over at https://github.com/dotMorten/WinUIEx/discussions

dotMorten commented 1 year ago

Looks like not only Google, but Facebook has also banned the use of embedded browsers and asking developers to use platform-provided authentication APIs on Android: https://developers.facebook.com/blog/post/2021/06/28/deprecating-support-fb-login-authentication-android-embedded-browsers/ At some point this'll likely come to Windows too.

Brosten commented 12 months ago

I'm also having this issue. The workaround suggested might be an option, but please fix! Issues like this makes developers run away from .NET MAUI. :(

Brosten commented 12 months ago

I have tried the workarounds from https://dotmorten.github.io/WinUIEx/concepts/Maui.html#use-winuiexs-webauthenticator-instead-of-net-mauis and from here https://github.com/dotnet/maui/issues/2702#issuecomment-1172988972

Both seem to do about the same thing. It does fire up a browser with the login page, however, the created url-parametes gives me 403/forbidden on our auth service. I can work around this, by using the second workaround and comment out the section manipulating the state parameter in the url. In this case, I'm able to login, but while doing so, my app isn't blocked in the background. I would have hoped this would be the case, or do I need to take care of that myself? The bigger problem is that when the browser return it doesn't return to my running app, but instead launches a new instance of the app and returns there... Does this has to do with my manipulation of the state parameter? Or am I doing some other mistake?

dotMorten commented 12 months ago

@Brosten please, anyone having WinUIEx issues, post them in my WinUIEx repo - let's keep this thread focused on the real issue.