Add Authentication to .NET MAUI Apps with Auth0

Thanks @andrea.chiarelli for the update.
I’ll wait until your next update on the secure API call.

I’m able to log in properly now but logout opens the browser with 404 error not found message. Not sure of the cause yet, my browser option has both start URL(https://xyz.com/v2/logout?client_id=xxx$returnTo=com.xyz.com) and endurl(postlogout redirect uri) that invokes the below line,
var browserResult = await oidcClient.Options.Browser.InvokeAsync(browserOptions);

After it returns browser result, browser gets opened with error and post closing the browser popup, app displays blank in black like crashed.
I only need to logout seamlessly without this browser being poped out. Is there any way to do that with Auth0? Also why this error occurs while logout?

Hi @gnanapriyasvmn ,

Was the 404 browser with the Windows workaround? If so, I also had the same behaviour, but I was able to work around this by forcing visibiliy of the panel OFF during the logout procedure to avoid this.

e.g.

private async void OnLogoutClicked(object sender, EventArgs e)
    {
#if WINDOWS
        Auth0WebViewInstance.IsVisible = false; // Fix for when logout is issued and even though valid, causes a 404 page
#endif
        var logoutResult = await auth0Client.LogoutAsync();

        if (!logoutResult.IsError)
        {
            HomeView.IsVisible = false;
            LoginView.IsVisible = true;
        }
        else
        {
            await DisplayAlert("Error", logoutResult.ErrorDescription, "OK");
        }
#if WINDOWS
        Auth0WebViewInstance.IsVisible = true;
#endif
    }

I also noticed a bit of strange behaviour when running the Windows workaround code and needed to disable visibility of the web view when on non-windows.

Hope that helps.

Boz.

3 Likes

Thank you for sharing your workaround @boz :pray:
Does it solve your issue @gnanapriyasvmn?

No, @andrea.chiarelli

Hi @boz ,

Appreciate your suggestion.

I’m getting this issue on the Android(not using windows project) platform.

Hey @gnanapriyasvmn,
Taking a closer look at the returnTo parameter of the URL you provide (https://xyz.com/v2/logout?client_id=xxx%24returnTo=com.xyz.com), I see it is not following the recommendation given in the article. The redirect URI must be in the URI format. The article suggests myapp://callback, for example.

I’m not sure if the value for the returnTo parameter in the URL you provided (com.xyz.com) is just a random string or reflects the actual structure of your URI.
I suspect it reflects the actual structure and this explains why you get the 404 error.

If this is the case, please, define a redirect URI value in the URI format.
Let me know if this helps.

My bad, for giving a random string.

I’m using my logout redirect URI in the returnTo string. Below are the exact start and end URL, I pass according to your article,

Login

starturl → https://abc.com/oauth2/v1/authorize?response_type=code&state=8cMvnHrls2xTAjjgewR1NQ&code_challenge=WQHzQqjgzFliUDZH8JJ23bCkm7Dx80WUHi3kiUw_E_8&code_challenge_method=S256&
client_id=abc&scope=openid%20offline_access
&redirect_uri=com.xxx%3A%2Fcallback

end url → myapp:/callback(this is my login redirect uri)

Logout

start url-> https://abc.com/v2/logout?client_id=aaa
&returnTo=com.xxx%3A%2Flogout

end url-> myapp:/logout(this is my post logout redirect uri. FYI, i have tried by replacing login redirect uri as well here)

By comparing both start url, there is vast difference, Is this in correct format as it needs to be?

Furthermore, while logging out below line never returns the result,

WebAuthenticatorResult result = await WebAuthenticator.Default.AuthenticateAsync(
new Uri(options.StartUrl),
new Uri(options.EndUrl));

and I have also added both login and logout redirect URI in my intent-filter of WebAuthenticationCallbackActivity.

I can also see the oidc.LoginAsync method returns LoginResult, but logoutasync gets called from Auth0Client returns BrowserResult. Is there any way to call the LogoutAsyc from oidc itself. If so, could you share any reference to implement it?

Hey @gnanapriyasvmn,
Looking at the URLs you shared, there are a few weird things.

First: are you using the same code shown in the article? At first look, it seems you made some changes and I can’t understand why you are getting those URLs.

Second: the RedirectUri value should be myapp://callback and not myapp:/callback. The latter is not correctly formatted.

Third: both the redirect_uri parameter in the login’s starturl and the returnTo parameter in the logout’s starturl shouldhave the myapp://callback value. It’s not clear to me why you are getting two different and unrelated values (this is why I’m asking if you are using the original code or did some changes)

Fourth: the endurl should always be myapp://callback

Please, check your code and configuration and make sure you didn’t apply changes that break those URLs building.

1 Like

Hello @andrea.chiarelli,
I have only updated endpoints in your sample, no code change.
I’m using the exact redirect URI defined in the okta admin for the MAUI app. These URIs are working fine in my Xamarin app even now.
Also, this redirect URI is working for MAUI post login, it’s redirecting as expected.

There seems to be an issue with the logout functionality. Could you share the logout steps required to implement oidc.LogoutAsync() if possible? I would like to check that method.

Sorry, but honestly I don’t understand what you mean by “I have only updated endpoints in your sample, no code change.”

If you didn’t change my code, the only change you have to do to integrate Auth0 is to replace the placeholders in the following code in MauiProgram.cs with your domain and client ID:


    builder.Services.AddSingleton(new Auth0Client(new()
    {
      Domain = "<YOUR_AUTH0_DOMAIN>",
      ClientId = "<YOUR_CLIENT_ID>",
      Scope = "openid profile",
      RedirectUri = "myapp://callback"
    }));

The endpoint URLs are built automatically.

There seems to be an issue with the logout functionality. Could you share the logout steps required to implement oidc.LogoutAsync() if possible? I would like to check that method.

The OidcClient library’s source code is available here if you want to take a look at it.
Bear in mind that this is not an Auth0 library. Reach out to the project maintainers for support.

1 Like

I really appreciate your suggestion, Thank you.

When I said no code change, other than client details I haven’t modified any of the logic, Only updated client configurations in mainpage.cs instead mauiapplication as singleton.
With your help, I’m now able to share the issue replicable sample with open client configurations of OIDC.
Not able to attach a sample here, so please find this reference [Android][OIDC v5.1.0] 404 browser not found error while logout · Issue #133 · IdentityModel/IdentityModel.OidcClient.Samples · GitHub

Thank you for sharing :pray:

1 Like

Hey @boz , @miroslav.bartl , @gnanapriyasvmn , and anyone else is interested, my article about calling a protected API in .NET MAUI has been published!

2 Likes

Hi @andrea.chiarelli,

Thanks for that article, works well.

One suggestion, is rather than storing the access token in a global variable as you’ve got in the section ’ Add a token holder ', would be to leverage the SecureStorage functionality that exists for MAUI (there’s a bit of setup required), but it means that it’s a bit more secure;

// Add the token
await SecureStorage.SetAsync( "OAuthToken", loginResult.AccessToken );

// Fetch the token
string oAuthToken = await SecureStorage.Default.GetAsync("OAuthToken");

// Remove the token
SecureStorage.Default.Remove("OAuthToken");

Doco for setup is here: Secure storage - .NET MAUI | Microsoft Learn

Cheers.

Boz.

Thank you for your feedback @boz.
Using SecureStorage was in my original plan, but there are several configuration steps and issues dependent on the specific platform that would have diverted the focus from the main topic of this article and made it longer and more complex.
But it may be worth putting in a note.
Thanks! :pray:

2 Likes

Yeah, understandable, but, security first right? :smiley:

Thanks again for developing the tutorials, makes life so much easier! :slight_smile:

Boz.

1 Like

Well, security is not compromised with my proposed solution. It’s even more secure than using SecureStorage :wink:
Thank you for appreciating my articles! :pray:

1 Like

I seem to have the same problem, but setting Exported = true didn’t help. It wants the minimum SDK version to be 19, but Visual Studio will not let me set this. Any suggestions?

Hi @mike17,
Unfortunately I’m not able to help you since my experience with Android is poor.
Have you tried looking to see if there is an open issue on the MAUI repo or to report it there?

1 Like

Hello! Firstly, thank you so much for this amazing tutorial, it has been hugely helpful.

I do also have a couple of issues, however, similar to gnanapriyasvmn above. In following your examples, I can sign in great, but I cannot sign out. When I try to log out, I get a 404 NOT FOUND error from Okta.

Now, it’s worth noting I’m using Okta, not Auth0 for this. I have an OIDC app set up in Okta using myapp://callback as the Sign-in and Sign-out URIs. Again, sign-in works great, but on sign out I get 404 and am not signed out “not found”. Moreover, it stays on the page instead of returning to the app with the error.

I’m guessing the logout piece isn’t working due to me using Okta instead of Auth0? Is there any chance you could help me get this going with Okta?

Thank you!

Hey @TheQuaybee,
Welcome to the Auth0 Community! :wave:
I’m glad that my tutorial was useful to you! :slightly_smiling_face:

Regarding your request, the code for the LogoutAsync() method is specific for Auth0.
For Okta, you should be able to log out by directly invoking the oidcClient.LogoutAsync() method with the ID token as extra parameter.
Take a look here for more info about the Okta /logout endpoint.

2 Likes