DEV Community

Cover image for Secure ASP.NET Blazor WASM apps and APIs with Azure AD B2C

Secure ASP.NET Blazor WASM apps and APIs with Azure AD B2C

Christos Matskas on August 12, 2020

Today's blog post is a bit on the cutting edge of .NET Core and Identity. We will be creating a secure Blazor Client (WASM) web app that authentica...
Collapse
 
woodpk profile image
woodpk • Edited

In your instructions, you did not include the need to add the class ScopesRequirement(). It would be nice to have a description of the class, why it is there, and what it does.

You did not mention that you have this package installed: Microsoft.Extensions.Http

Collapse
 
christosmatskas profile image
Christos Matskas

Hi @woodpk ! You're absolutely right! Great catch, I will update the blog asap. This is a gross omission on my behalf :(

Collapse
 
woodpk profile image
woodpk

I may need some direction in getting my implementation of your instructions to work correctly. I have been able to link ADB2C with the blazor client project, but when attempting to route through ADB2C to access the .net API, i am getting an error telling me that the config resource at that endpoint does not exist, but it also gives a "DENY" error:

System.InvalidOperationException: IDX20803: Unable to obtain configuration from: 'PhoenixRisingCounselingServices.b2...'.
---> System.IO.IOException: IDX20807: Unable to retrieve document from: 'PhoenixRisingCounselingServices.b2...'. HttpResponseMessage: 'StatusCode: 404, ReasonPhrase: 'Not Found', Version: 1.1, Content: System.Net.Http.HttpConnectionResponseContent, Headers:

Message in the

tag is:

404 - File or directory not found.


The resource you are looking for might have been removed, had its name changed, or is temporarily unavailable.

And here is the end of the stack trace:
at Microsoft.IdentityModel.Protocols.HttpDocumentRetriever.GetDocumentAsync(String address, CancellationToken cancel)
at Microsoft.IdentityModel.Protocols.OpenIdConnect.OpenIdConnectConfigurationRetriever.GetAsync(String address, IDocumentRetriever retriever, CancellationToken cancel)
at Microsoft.IdentityModel.Protocols.ConfigurationManager`1.GetConfigurationAsync(CancellationToken cancel)
--- End of inner exception stack trace ---

Thread Thread
 
christosmatskas profile image
Christos Matskas

Hi @woodpk , there seems to be some typo or issue with your metadata endpoint. Can you doublecheck and get back to me... feel free to email me at iddevsoc@service.microsoft.com to work this out

Thread Thread
 
woodpk profile image
woodpk

Don't know why it cut that text off... i'll email as that might work out better.

Collapse
 
christosmatskas profile image
Christos Matskas

Updated... thanks for your feedback!

Collapse
 
gearsolutionschile profile image
gearsolutionschile

Hello, here in Chile. Make a blazor web assembly application connected to azure B2C but I have a problem sometime the token expires and if you give the page refresh an error like this appears.
Microsoft.AspNetCore.Components.WebAssembly.Rendering.WebAssemblyRenderer [100]
Unhandled exception rendering component: null_or_empty_id_token: The idToken is null or empty. Please review the trace to determine the root cause. Raw ID Token Value: undefined
ClientAuthError: null_or_empty_id_token: The idToken is null or empty. Please review the trace to determine the root cause. Raw ID Token Value: undefined
any ideas?

Collapse
 
thatmouse profile image
ThatMouse

Do you have a Blazor Server how-to? There are wildly different ideas out there on connecting to Azure AD. Some using a template/scaffolding approach which is hard to follow without starting a new project. Some using Microsoft.AspNetCore.Authentication.AzureADB2C.UI and some using Microsoft.Identity.Web.

Collapse
 
christosmatskas profile image
Christos Matskas

Hi @thatmouse - here's the official blog post we published on Blazor Server + AAD.
developer.microsoft.com/en-us/micr...

Our guidance is to use the Microsoft.Identity.Web going forward.

Collapse
 
thatmouse profile image
ThatMouse

Thank you, I will focus on that project, it's on github. It uses the new project template so it is not clear what magic that template does.

Collapse
 
danich93 profile image
Dan

Nice tutorial. The sad part about MSAL for webassembly at the moment is that it only really works out of the box for simple scenarios like this one. Currently it can't even support password reset without additional hacks. The same goes for profile edit/registration policy. Those simply don't work out of the box.

Collapse
 
mihaimyh profile image
Mihai Dumitru

Hi, is there a way to have custom roles defined in B2C and to be used within Blazor Wasm and Api? For example a role for an admin user which exposes other parts of the UI and can call specific API endpoints?

Collapse
 
christosmatskas profile image
Christos Matskas

B2C doesn't provide roles. However, JP has been working on a project to create a B2C compatible role-management solution. Check out our YT video on this: youtu.be/I_ddlSOHvwk

Collapse
 
lockhartlimited profile image
Lockhart Software

Hi Christos

Thanks for your excellent articles.

When will Microsoft.Identity.Web be available for Blazor WASM?

Thread Thread
 
christosmatskas profile image
Christos Matskas

Microsoft.Identity.Web is a server-side library and therefore can't be used in Blazor WASM which is client-side. Blazor WASM uses a flavor of @azure/msal-browser which is designed for JS (client-side apps). I hope this makes sense but feel free to reach out if you have more questions. Make sure to join our Discord as well for more Identity Qs aka.ms/425Show/discord/join

Thread Thread
 
lockhartlimited profile image
Lockhart Software

Thanks Christos. This makes sense.

Collapse
 
guillemsolersuetta profile image
guillem-soler-suetta

I want to implement a Login/Sigin in a Blazor Server App but they require that the UI needs to be from the same domain in other words that when I Sign In I don't want to use a template or Azure redirection. It has to reach for another Net Core Api that connects with Azure AD B2C. How this could be done? Some mentioned ROPC but Microsoft don't recommend it, and other pointed me to this samples github.com/Azure-Samples/active-di... but I don't know if one of those could be use to do what I need.

Thank you very much in advance.

Collapse
 
christosmatskas profile image
Christos Matskas

Hi @guillem, thanks for reaching out. If your front end app (Blazor Server) doesn't need call the api securely, then you can skip authentication in the front end all together. However, I'm struggling to understand your scenario. Are you planning on taking the user's credentials in your front end and pass them to the API? Is the plan for your API to authenticate and validate the users using B2C? Thanks, CM

Collapse
 
nhwilly profile image
nhwilly • Edited

Very cool stuff. Thank you for doing this. I am having a problem setting up the API as it is complaining about

services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
    .AddMicrosoftWebApi(options =>
 {
Enter fullscreen mode Exit fullscreen mode

It can't find the AddMicrosoftWebApi method. I can't find any reference to it, either. Is there a new approach? I checked the github code and it hasn't changed.

I'm using: Assembly Microsoft.AspNetCore.Authentication, Version=5.0.0.0

Thanks in advance.

Edit: I loaded the old code and it's there, so it must have disappeared in a subsequent release.

Collapse
 
nhwilly profile image
nhwilly

I think I found it, but I don't know why it wasn't showing up earlier. I know I looked.

It's called AddMicrosoftIdentityWebApi now.

Collapse
 
finnurhrafn profile image
FinnurHrafn

Thanks for this detailed summary. After going through the settings on the B2C portal and building the WASM client with the supplied command I started the app and tried to log in:
Then I got: "Checking login state..." and nothing more. After some head scratching I hit F12 and got a clue to what was wrong.
In the appsettings.json the line for "Authority" was incorrect. The forward slash after the xxx.b2clogin.com was missing. Adding that fixed the problem. It seems I omitted the forward slash.
I just learned that the instructions have to be followed to the letter :)

Collapse
 
christosmatskas profile image
Christos Matskas

HI @finnurhrafn , thanks for the kind comments and the feedback. And I'm glad you were able to resolve the issue. I have to agree that attention to detail is important :) - moreso in programming than anything else! Keep up the great work and ping us if you have any more issues

Collapse
 
victorioberra profile image
Victorio Berra

Why do you not validate the issuer? ValidateIssuer = false?

Collapse
 
waterninja profile image
waterninja

Are you available for consulting Christos?
I just cannot get this to work.

Collapse
 
waterninja profile image
waterninja • Edited

I found the problems, after a lot of debugging, I finally got the project down to some sensible errors. In Program.cs, in the API, I mistyped my scope and I had a Json Deserialization problem with the new .Net 7 template on the Wasm side. Out of the box from the .Net 7 template setup, the WeatherForecast class uses a "DateOnly" property. GetFromJsonAsync failed when deserializing DateTime to DateOnly in FetchData.razor