Add Auth0 Authentication to Blazor Web Apps

Thanks for the great article. There is so little information about how to configure the client components to use security when they are calling an API.

Are you able to do ‘Part 2’ of the article and show how we can extend this solution to call an API endpoint (maybe secured by Auth0 as well?), and use the access token to call an external API? This is the big missing piece to making Blazor .Net 8 apps useful!
Thanks!

Hey @ripteqdavid,
Thank you for appreciating my article and welcome to the Auth0 Community!

Actually, the topic of calling an API has been asked a number of times. I hope to cover this soon.
In the meantime, I invite you to take a look at my suggestions on calling “internal” and external APIs here and here

Hi Andrea,

Great article. And i am slowly digesting it.
My case looks like a bit different (as i understand your article). In my case I would like to have a .Net 8 Blazor WebApp in Interactive WASM Rendering mode which will call a serverless Azure function secured by OIDC identity provider.

What would you suggest in this case. My server calls are directly from browser to Azure function. Is there an example i can refer to ?

Sorry my bad. I did not see your reply here to another question. Looks like the same question.

"Thank you for appreciating my article and welcome to the Auth0 Community!

Actually, the topic of calling an API has been asked a number of times. I hope to cover this soon
"

Hi,

Thank’s for tutorial it’s interresting, but if i can expose my opinion, only show how to used in Blazor app is not enough, secure and after didn’t have a concret sample for calling API, it’s quite “useless” ? Sorry if words is too hard, but for some it’s blocking, because having API for data and cannot be call ?

For my part i’ve used :

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


app.MapForwarder("/{**catch-all}", "https://localhost:5000", transformBuilder =>
            {
                transformBuilder.AddRequestTransform(async transformContext =>
                {
                    var accessToken = await transformContext.HttpContext.GetTokenAsync("access_token");
                    transformContext.ProxyRequest.Headers.Authorization = new("Bearer", accessToken);
                });
            }).RequireAuthorization();

If i’ve connected and go manualy on /api/my-url it’s forward with AccessToken
If i try from HttpClient from Page it’s try to call auth flow :frowning:

Kr,

Hey @Hantse,
Writing a follow up of this article focused on calling protected APIs is in my plans.
In the meantime, I suggest using different approaches depending on whether the API is internal or external to your application.
See this answer for my suggestion for the two approaches.

I get the following error running my application and a cloned copy of yours from github with my auth0 credentials in.

InvalidOperationException: IDX20803: Unable to obtain configuration from: ‘https://https://dev-opynqcjq58yhxawc.us.auth0.com/.well-known/openid-configuration’.

Hey @brianrhody,
Looks like you assigned your tenant URL (https://dev-opynqcjq58yhxawc.us.auth0.com) instead of your tenant domain (dev-opynqcjq58yhxawc.us.auth0.com) to the Domain key in appsettings.json.

Thank you for writing this article it made switching over to the new Blazor model much easier. The question that I have is how would I be able to intercept the creation of the ClaimsPrincipal so that I can have it pull additional claims from the JWT token?

Prior to switching to this new model I was able to accomplish this by calling,

and passing in a custom ClaimsPrincipal factory.

As far as I can see, your code snippet is for Blazor WebAssembly. In the Blazor model discussed in this article, the authentication happens on the server side so you can’t use AddAccountClaimsPrincipalFactory().

I’m not sure about what you wan to achieve, but if you just need to access all the claims from the ID token, you can do it through the AuthenticationState. Take a look at this example:

var state = await authenticationState;

var myClaimValue = state.User.Claims
    .Where(c => c.Type.Equals("myClaimName"))
    .Select(c => c.Value)
    .FirstOrDefault() ?? string.Empty;

I hope this helps.

We have added custom claims for our users in Auth0, for example key: “permission”, value: “customer.read”, and the only way to retrieve them is by reading the Access Token that is returned from Auth0 when a user logs in. I just cannot figure out where I can intercept the point that the Access token is turned into the ClaimsPrincipal object. This is what is in the the Jwt token contains

image

But this “permissions” do not come through when the ClaimsPrincipal object is created.

Hey @wdavis,
The access token is NOT mapped to the ClaimsPrincipal object. The ClaimsPrincipal object contains ONLY the claims coming from the ID token.

The access token is intended for calling a protected API, and only the API should inspect it.

See here for the difference between ID and access tokens.
See here to learn how to check permissions on the API side.

If for some reason you need additional claims in your ID token, you can add them using Actions.
See here for an example of adding custom claims to an ID token using Actions.

If in your case the API is implemented in the same Blazor app, I would not use token-based protection. Take a look at this article to have more context on calling an API.

So, How would I be able to access the user’s permissions so that I can use them in the UI?

You should use Actions to add permissions to the ID token as custom claims (see here to learn how to do this).
If your UI does not need the granularity of permissions, you may consider creating roles instead. However, this depends on your specific use case.