Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

WebAuthenticator OpenId Connect Support #195

Closed
Mike-E-angelo opened this issue Nov 8, 2024 · 11 comments
Closed

WebAuthenticator OpenId Connect Support #195

Mike-E-angelo opened this issue Nov 8, 2024 · 11 comments

Comments

@Mike-E-angelo
Copy link

Thank you very much for making this extension. 🙏 I have been investigating Maui + Blazor Hybrid functionality and am currently exploring authentication, which led me to the disappointing discovery that WebAuthenticator is not available for Windows. 💥

I also found the newest eShop which makes use of the WebAuthenticator and have tried to use WinUIEx's there instead.

It appears the eShop solution uses OpenId Connect, and WinUIEx supports Oauth2, which makes it not work as expected. Essentially, another window opens and leaves the original opening window open without a response.

I took a peek at the resulting callback URL and the properties there are not what WinUIEx is expecting, which I believe is resulting in this condition.

Please let me know if I have something fundamentally misunderstood. Thank you for your consideration.

@dotMorten
Copy link
Owner

dotMorten commented Nov 8, 2024

Could you please provide a sample that reproduces the issue and describe in more detail what the actual issue is (something more detailed than "not work as expected"), as well as describe what you did to the app to enable WinUIEx web authenticator?
I haven't used OpenId, but from the doc it sounds like it's a slightly different thing
image

@Mike-E-angelo
Copy link
Author

Mike-E-angelo commented Nov 8, 2024

Thank you for your fast reply!

To start I used the SLN from eShop:
https://github.com/dotnet/eShop/blob/main/eShop.Web.slnf

(I downloaded the entire repository to my machine)

Then I found the usage of WebAuthenticator here:
https://github.com/dotnet/eShop/blob/main/src/ClientApp/Views/MauiAuthenticationBrowser.cs#L13

And updated it to thus:

public class MauiAuthenticationBrowser : IBrowser
{
    public async Task<BrowserResult> InvokeAsync(BrowserOptions options, CancellationToken cancellationToken = default)
    {
        try
        {
#if WINDOWS
            var result = await WinUIEx.WebAuthenticator.AuthenticateAsync(new(options.StartUrl), new(options.EndUrl));
#else
            var result = await WebAuthenticator.AuthenticateAsync(new(options.StartUrl), new(options.EndUrl));
#endif

            var url = new RequestUrl("maui://authcallback").Create(new(result.Properties));

            return new BrowserResult {Response = url, ResultType = BrowserResultType.Success};
        }
        catch (TaskCanceledException)
        {
            return new BrowserResult {ResultType = BrowserResultType.UserCancel};
        }
    }
}

And then the App.xaml.cs:
https://github.com/dotnet/eShop/blob/main/src/ClientApp/Platforms/Windows/App.xaml.cs#L15

To this:

public partial class App : MauiWinUIApplication
{
    /// <summary>
    /// Initializes the singleton application object.  This is the first line of authored code
    /// executed, and as such is the logical equivalent of main() or WinMain().
    /// </summary>
    public App()
    {
        if (!WinUIEx.WebAuthenticator.CheckOAuthRedirectionActivation())
        {
            this.InitializeComponent();
        }
    }

    protected override MauiApp CreateMauiApp() => MauiProgram.CreateMauiApp();
}

I also had to add the protocol registration (maui) in AppxManifest.

You do have to have Docker for Windows installed. After this, it's a matter of:

  1. Launching CTRL-F5 on eShop.AppHost and waiting for all services to launch/be ready
  2. Launching F5 on ClientApp
  3. Once in the ClientApp you will have to switch from Mock services to "real" services:
  4. Then press Login and you should see that two windows are opened after successful authentication: https://i.imgur.com/03JQipk.mp4

For reference, here is the callback URL that is returned from the OpenID Connect:

{maui://authcallback/?
	code=F87099D283BB467DDA510403F39148BD2E3E08E5609F7E979DA91E50162B7DEA-1
	&
	scope=openid profile basket orders offline_access
	&
	state=ECKb-Z7lNECI2rccWW-TvQ
	&
	session_state=GXn6KXDGrdLP5qKoBVC93Xn5lKuV04I8W0IPFy8FvII.76434C58166AC795747EB7EE71220DF2
	&
	iss=https%3A%2F%2Flocalhost%3A5243
	}

I know this is a bit involved, but it's what I have been using for the afternoon as I explore this. I have zero Maui/WinUI experience so this is it at the moment. That stated, please let me know if there is any further information that I can provide to assist.

@dotMorten
Copy link
Owner

dotMorten commented Nov 8, 2024

When it does the redirect in the browser to maui://, do you not see browser asking you to open the link in the eShop app? If not that means the registration for the app in the appx manifest isn't set up right. WinUIEx would never even get to be active if the redirect back to the app doesn't work.
Also make sure the app is running as packaged (it looks like it is from the eshop sourcecode)
Lastly the state parameter seems fishy. There should be information about how to continue the task, so I'm wondering if there's a bug in the server side code that causes it to not preserve the state parameter.

@Mike-E-angelo
Copy link
Author

When it does the redirect in the browser to maui://, do you not see browser asking you to open the link in the eShop app?

If I understand correctly, yes I do see it:
image

After pressing Open the 2nd window opens (please let me know if I have something misunderstood).

Also make sure the app is running as packaged (it looks like it is from the eshop sourcecode)

This may be the problem. 🤔 I am indeed pressing F5 and not packaging that I can see. I tried looking (and searching) for this and did not see how to do this. Any pointers would be appreciated.

Lastly the state parameter seems fishy. There should be information about how to continue the task, so I'm wondering if there's a bug in the server side code that causes it to not preserve the state parameter.

As I understand it, this is OpenID and not Oauth2, which may be different (but I could be misunderstanding of course).

@dotMorten
Copy link
Owner

ok in that case it's the state parameter that your server is messing up. This state parameter is used to ensure the redirect is sent back to the correct application and completes the correct pending Task. It must preserve this parameter which you'll also see in the first URL that is being opened in the browser. I'd suggest you debug that part of the service and see why it's returned something completely different.

@Mike-E-angelo
Copy link
Author

Mike-E-angelo commented Nov 8, 2024

That's it. Thank you. I can confirm that the /connect/authorize passes the values that WinUIEx expects:

https://localhost:5243/connect/authorize
	?client_id=maui
	&
	request_uri=urn%3aietf%3aparams%3aoauth%3arequest_uri%3a2570D19BBB1F7FED8A9FCF756C6775A8131214F6FF3518E48F995C9DDABBAAC2
	&
	state=%7b%22appInstanceId%22%3a%22%22%2c%22signinId%22%3a%2236b7da9a-b9e4-4828-b315-f8e6fa44cc4b%22%7d

But then when it gets into the application, it is different:

maui://authcallback/?
	ode=B985916E25D787B867DCDC8C96413A7E15F416B79B61D279850ACDE2F748977E-1
	&
	scope=openid profile basket orders offline_access
	&
	state=DyjXbgvFk1k6NdSsZ-2jiA
	&
	session_state=Jg2lFiZZMthU_f6a2YdXZXci1aHApme-3zaltAarG_c.9EAAE4B3A1F1C7175692A84F7EE88845
	&
	iss=https%3A%2F%2Flocalhost%3A5243

I'll dig further to see if I can figure this out. Thank you for your guidance. 🙏

@dotMorten
Copy link
Owner

Thanks for confirming

@dotMorten
Copy link
Owner

and thanks for the donation too 💯

@theorska
Copy link

Hello @Mike-E-angelo and @dotMorten,

I have recently started developing with .NET MAUI and I encountered this issue too. I wanted to detail a bit on what my solution was and if this is something that needs to be addressed for other users.

How did I encounter this issue?

On a brand new project I added the OidcClient and WinEUEX.WebAuthenticator as described in most guides. I got errors that the state could not be parsed and after the login, the identity provider was returning a different state (exactly as above).

Investigation

I found that OidcClient will make a call to the identity provider before the authentication process starts in WinEUEX.WebAuthenticator. In this call, it will use a randomly generated state unless a different state generation is chosen in OidcClientOptions. This state was then returned by the identity provider, even though the new state with appInstanceId and signinId was set.

** Solution **
I am using Duende Identity Server as my provider. For the WinEUEX.WebAuthenticator to work, I had to set:

builder.Services.AddIdentityServer(options =>
{
    options.Endpoints.EnablePushedAuthorizationEndpoint = false;
})

mentioned here.

This setting is not available below Business Edition in my case, but you can check if this is the reason for what you are experiencing with your provider as well.

** Open Questions **

With OidcClient at the moment this feature is not working, as the state generated by OidcClient will be returned inside WinEUEX.WebAuthenticator, not the one created by it. Should this be supported by WinEUEX.WebAuthenticator in the future?

@Mike-E-angelo
Copy link
Author

Ahhh that's probably it @theorska thank you for that insight. I did indeed spend some additional time looking into it, and my estimation was exactly as you stated, that there was some state being persisted somewhere and referenced by a key that is later loaded on the return. In this case, I was doing the work for the client and there was only so much time we had to track this down. So I wasn't able to complete this task on time. We may revisit it in the future however and I will look further into this. 👍

(I was also going to update this thread on any further findings as well if I was successful)

@dotMorten
Copy link
Owner

Thanks @theorska I'll make sure the new OAuth APIs in Windows App SDK 1.7 knows about this issue too, as they also rely on the state parameter (their implementation is near-identical to WinUIEx' in many ways)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants