Add Auth0 Authentication to Blazor Web Apps

Let’s find out how to add Auth0 authentication to the new Blazor application model introduced in .NET 8.
Read more…

2 Likes

Share your thoughts or questions in the comments – we’d love to hear from you!

Thank you! Just what I needed this morning! I did not need the WebAssembly part as I just wanted the new template with Blazor Server for .NET 8 and this got me there with minimal fuss! Appreciate your efforts and contribution for this new template style!

1 Like

Hey @rev23dev, glad to know it helped you!
Thanks for your kind feedback!

Thanks for the post!
I was able to make this work, but I’m having trouble getting the bearer token from within a component. Am I missing something?

Hey @fedemartino,
The article does not cover the access token management.
What is your scenario? What do you mean by “getting the bearer token from within a component”?
What API are you going to call? An API implemented within your Blazor application or a separated API?
If you can provide more details I can try to suggest a possible solution.

Thanks for taking the time to reply. My post was late last night and clearly did not have any relevant info of my scenario. So here goes:
I’m trying to invoke a separate API which also uses Auth0. To make that request I need to include the bearer token and so I need to be able to retrieve that token from the authenticated user.
The API request will be done from a service class that is DI into a blazor component.
I found this article that covers this exact scenario: Server-side ASP.NET Core Blazor additional security scenarios | Microsoft Learn and am able to retrieve the token and store it in the TokenProvider. However, when that same TokenProvider is DI into the service that makes de API call, all values are null.
I’m guessing my problem has to do with this: Blazor SSR: per-user state management · Issue #47796 · dotnet/aspnetcore (github.com) and there is workaround described here: Per-User Blazor 8 State | Rockford Lhotka, but I have not had time to test it yet. Will probably try it later today

Hi Andrea

Very good article. But probably next step for everyone would be to create authenticated http call between Server and Client so could you extend it with the authenticated http call from Counter component in BlazorIntAuto.Client project which have render mode to InteractiveAuto to the BlazorIntAuto?

Thanks
Martin

1 Like

Hi @martin.gramblicka,
Thank you for appreciating my article and suggesting for the next step.
Honestly, to call an API implemented in the server-side application from the WebAssembly side, I would stick with the classic cookie-based authentication. I would avoid adding more complexity to an already complicated situation.
In other words, I would use the cookie authentication support that AddAuth0WebAppAuthentication() already enables by default and simply call the protected API in the WebAssembly client via the HttpClient.
How does this sound?

1 Like

Ahh thanks i didn’t realized it. I thought we need to generate bearer token and pass it with each request. Thanks it works fine.

1 Like

I concur with this being exactly what I needed. I was going round and round because I think the Auto mode is the E-Ticket. But now I’m going round and round again because I want to use AWS API Gateway to CRUD with a Lambda and Dynamo DB. That at least the API needs JWT. Do you have any tips or places where I can see some code to make that work with this code? I am login on Auth0 just fine but how do I get a JWT token and pass it to the WASM client???

Hi @MickCG,
Honestly, I would avoid passing the access token to the WASM client.
I would implement a sort of BFF instead.

In other words, I would configure the Auth0 SDK to request an access token for your external API via the WithAudience() method.
Then I would create an API exposed to the WASM client, secured through classic cookie-based authentication.
This API will map to the external API. When your WASM client calls the internal cookie-based API, your code will call the external API using the access token.

Take a look at this article to have an idea of how to implement BFF in ASP.NET Core.

Does this make sense?

cc: @fedemartino Maybe this can help you as well

Somewhat, at least get’s me started, thanks!

Excellent article Andrea. I did run into a problem. I cloned your repo as is and configured my Auth0 application as directed, however after logging in and redirecting back to your application running locally I see this error page. I am on the latest updates for dotnet 8. Any ideas on the issue? Could something be misconfigured?

An unhandled exception occurred while processing the request.
OpenIdConnectProtocolException: Message contains error: 'unauthorized', error_description: 'Access denied.', error_uri: 'error_uri is null'.
Unknown location

AuthenticationFailureException: An error was encountered while handling the remote login.
Microsoft.AspNetCore.Authentication.RemoteAuthenticationHandler<TOptions>.HandleRequestAsync()

Stack Query Cookies Headers Routing
OpenIdConnectProtocolException: Message contains error: 'unauthorized', error_description: 'Access denied.', error_uri: 'error_uri is null'.

Show raw exception details
Microsoft.IdentityModel.Protocols.OpenIdConnect.OpenIdConnectProtocolException: Message contains error: 'unauthorized', error_description: 'Access denied.', error_uri: 'error_uri is null'.
AuthenticationFailureException: An error was encountered while handling the remote login.
Microsoft.AspNetCore.Authentication.RemoteAuthenticationHandler<TOptions>.HandleRequestAsync()
Microsoft.AspNetCore.Authentication.AuthenticationMiddleware.Invoke(HttpContext context)
Microsoft.AspNetCore.Diagnostics.DeveloperExceptionPageMiddlewareImpl.Invoke(HttpContext context)

Show raw exception details
Microsoft.AspNetCore.Authentication.AuthenticationFailureException: An error was encountered while handling the remote login.
 ---> Microsoft.IdentityModel.Protocols.OpenIdConnect.OpenIdConnectProtocolException: Message contains error: 'unauthorized', error_description: 'Access denied.', error_uri: 'error_uri is null'.
   --- End of inner exception stack trace ---
   at Microsoft.AspNetCore.Authentication.RemoteAuthenticationHandler`1.HandleRequestAsync()
   at Microsoft.AspNetCore.Authentication.AuthenticationMiddleware.Invoke(HttpContext context)
   at Microsoft.AspNetCore.Diagnostics.DeveloperExceptionPageMiddlewareImpl.Invoke(HttpContext context)

I was actually able to get this to work. Turns out it was an issue with my tenant in Auth0. I was able to delete and spin up a new tenant and all worked fine.

Is there any plan for this same tutorial but with JWT instead of cookies. Specifically looking for help getting a solution for Blazor Web App with a razor class library shared with a blazor hybrid maui application. All would be calling a web api so thus need to make tokens work.

Hi @eruvalca,
Glad to hear that you managed to solve your problem.

Related to your request, what do you mean by “this same tutorial but with JWT instead of cookies.” Are you planning to call an external API and need an access token? :thinking:
In this case, I suggest using the approach outlined here

For the Blazor Hybrid MAUI app, you should combine the approach explained in this article with this one. Be aware that the first article does not use the new MAUI SDK, but you should because it simplifies a lot the code. I need to find some time to update it sooner or later :slightly_smiling_face:

Really great article…Thank you for publishing it – it seems, however, when I wire this in, it looks like it is using implicit flow, instead of PKCE – how would the code change to use PKCE instead?

Also, I am struggling to get the redirect_url parameter to pass all the way through the authentication process – it passes from the login screen correctly to the auth component, but somewhere in the redirects, it loses it, because when it comes back, it always returns to / for me?

TIA

Hi @chadwick.posey,
Welcome to the Auth0 Community! :wave: Thank you for appreciating this article :slightly_smiling_face:

You are right: the Auth0 ASP.NET Core Authentication SDK uses the Implicit Flow with Form Post by default. This is ok as long as you just need an ID token (i.e., just user authentication).

If you need an access token, i.e., you need to call an external API, you have to switch to the Authorization Code Flow. You can do this very easily using the SDK, as shown in the following code:

builder.Services
    .AddAuth0WebAppAuthentication(options => {
      options.Domain = builder.Configuration["Auth0:Domain"];
      options.ClientId = builder.Configuration["Auth0:ClientId"];
    })
    .WithAccessToken(options =>
    {
        options.Audience = Configuration["Auth0:Audience"];
    });

Of course, you need to specify the API audience.

Please, take a look at this doc for some code examples using the Auth0 ASP.NET Core Authentication SDK.

Related to the redirect_uri issue, I’m not sure I correctly understand :thinking:
Are you saying that passing the URI to the WithRedirectUri() does not work as expected? If so, can you provide some code to analyze?

The above code yields an error saying that a client secret or a client assertion must be provided in order to request an access token. We are merely interested in securely authenticating users, and Okta suggests (actually requires) PKCE for SPA applications.

See: Implement authorization by grant type | Okta Developer

and

Your tutorial is the closest I’ve come to getting Blazor in .NET 8 working with our Okta implementation, but it still isn’t quite working when using Okta – it works great using auth0 (as you would expect)… There just isn’t a lot out there for .NET 8 authentication with Blazor

Hey @chadwick.posey,
Sorry, I missed to suggest that you need to use your client secret to get an access token, as this example from the SDK docs shows.

Keep in mind that the Blazor solution contains two projects: a Blazor Server project and a Blazor WASM project. The project that communicates with Auth0 is the Blazor Server project. This is not a SPA application and so you can use the secret for the Authorization Code Flow without any problem.

Getting an access token this way is meant for calling an external API, that is an API that is not implemented in this Blazor solution. That API must be called by your server code, not by your WASM client.

If you need that your Blazor WASM client calls an API implemented by the Blazor Server in this solution, I suggest using the classical cookie based approach, as mentioned here.

As you said, this article is intended for Auth0. However, I think that the general approach should be valid regardless of the specific Identity provider.

Finally, I agree with you: there is not much documentation for Blazor authentication in .NET 8; it is not covered well by the official documentation either.