Open LapinskasL opened 4 months ago
Hello @LapinskasL ... This article is only about integrating Identity with Blazor (which it calls out in the intro). Tokens/token expiration/token renewal are identity provider subjects covered by the Entra/MS Identity Web docs (or OIDC docs if you use OIDC with Entra) and perhaps .NET MAUI docs/samples. This isn't an article about how to implement Identity generally.
WRT the roles not working with AuthorizeView
, it's probably because the role claim is missing or not mapped to the new claims identity properly ... again, something covered in external doc sets (for example, part of the MAUI tutorial series that deals with roles, Entra doc: Configure the role claim, OIDC role claim mapping, etc.).
The .NET MAUI docs point to a tutorial in the External ID doc set's tutorial area :point_right: https://learn.microsoft.com/entra/external-id/customers/tutorial-mobile-app-maui-sign-in-prepare-tenant.
@BethMassi ... These are the potential cross-links that I scared up for an Additional Resources section added to this article. Which of these are these OK? Are there any other resources that I should cross-link?
I'll make checkboxes out of these, and you can edit this and check off the ones I should use if that's fast π ..........
@guardrex Thanks for all the info. I was able to gather some bits and improve my code.
However, the information on how to integrate Entra ID auth into a Blazor Hybrid app is scattered across many places. You can see this by the amount of links you needed to provide and how only a potion of information within them is applicable to Blazor Hybrid.
I'd think Microsoft would have a single page dedicated to adding and explaining Blazor Hybrid auth with Entra ID. They're both Microsoft products after all and, ideally for you, I should have minimal trouble guiding myself into a greater dependency on your products. My research tells me I'm not alone in struggling with this specific issue.
That said, I do think atm I have enough figured out to be sufficient for a production environment. It just took really long to put the pieces together.
Also, I am struggling with mapping the role claim name. I don't have the .AddOpenIdConnect()
method and having cookie authentication does not make sense.
To be clear, I do appreciate all the help. I understand Blazor Hybrid is new and will take effort and time to improve and provide solid documentation, especially when you have thousands of other people asking you for stuff.
how to integrate Entra ID auth into a Blazor Hybrid app is scattered across many places
I'm sure @BethMassi just heard your feedback on that. I'm just a worker π ... a worker π¦π ... on Blazor docs. I'm an Aquent contractor limited to working on the Blazor docs in this repo, and management ... such as Beth and Dan Roth ... decide how the overall content is organized, especially when the articles span different documentation teams/people.
I should explain that docs are more compartmentalized than most people think: Azure, Identity, Graph API, MAUI, and Blazor docs are handled by different doc folks/teams, and that can explain why things might seem a little uncoordinated in these layered technology situations.
a single page dedicated to adding and explaining Blazor Hybrid auth with Entra ID
It can be accomplished to an extent ... a basic use case ... in a tutorial or in an article that explains how a provided sample app works. However, it's impossible to cover security these days in a single reference article because the technologies are so complex and have so many features covering so many scenarios. When a tutorial (or sample+article) is placed, the author has to make a lot of choices about what scenarios/features to include, and leaving something out, such as roles, does often generate a request for additional coverage.
WRT to roles and Blazor Hybrid ...
The first part of the coverage is this ...
BTW @BethMassi on that lead-in text to the code snippet, readers might fare better with just being given the full class, the full method, or a diff
block.
... and that refers to making changes in the context of this ...
The second piece is in our article here ...
... in spots where the claims identity is created (new ClaimsIdentity()
).
I'll see about getting roles via Entra ID working here, and then I'll see if I can get that into this Blazor article. I might be able to work on this today. I just need to see if anything else is pressing at the moment.
I was just reviewing the issues, and a 'please add roles' request came in for the BWA+OIDC sample app, too ...
https://github.com/dotnet/AspNetCore.Docs/issues/32512
It's quite a common request due to the ubiquity of role use in production .NET apps.
The prereqs of the third article (my first link in the preceding comment) are ...
BUT ... The first one is Part 3 of the series βοΈ ... and it makes it clear that you must complete Part 2 before that ...
BUT AND™ π ... Part 2 relies on Part 1 and the second article βοΈ requires the tenant to have been created in the first place, so it also relies on Part 1.
I think what I'll end up floating for the Blazor doc is an ordered reading/cross-link list before/after whatever code sample(s) provided.
Versioning doesn't seem to be in use ...
In the Additional information window, choose .NET 7.0 and select Create.
Because of this approach of setting the app's namespace via project creation ...
In the Configure your new project window, Project name must be set to SignInMaui. Update the Solution name to sign-in-maui and select Next.
... it makes it more challenging to implement the guidance in an existing app. It might be better to just have the user update the namespaces of the added files.
NRTs not in use, so static analysis throws quite a bit.
There's no AppShell.xaml
file in my MAUI app.
Unfortunately, I've run into too many errors that I don't recognize and can't resolve, so I won't be able to adopt an in-place adoption of Identity.
I'll try the sample app next.
No π²π² OOB. The sample targets 7.0, which throws unsupported errors. Even updating to target 8.0 and using the 8.0 SDK, it throws ...
The type or namespace name 'MauiWinUIApplication' could not be found (are you missing a using directive or an assembly reference?) sign-in-maui (net8.0-windows10.0.17763.0) 2-sign-in-maui\Platforms\Windows\App.xaml.cs 13
The type or namespace name 'LaunchActivatedEventArgs' could not be found (are you missing a using directive or an assembly reference?) sign-in-maui (net8.0-windows10.0.17763.0) 2-sign-in-maui\Platforms\Windows\App.xaml.cs 33
The type or namespace name 'MauiWinUIWindow' could not be found (are you missing a using directive or an assembly reference?) sign-in-maui (net8.0-windows10.0.17763.0) 2-sign-in-maui\Platforms\Windows\App.xaml.cs 38
'App' does not contain a definition for 'InitializeComponent' and no accessible extension method 'InitializeComponent' accepting a first argument of type 'App' could be found (are you missing a using directive or an assembly reference?) sign-in-maui (net8.0-windows10.0.17763.0) 2-sign-in-maui\Platforms\Windows\App.xaml.cs 21
Sometimes, my preview VS π₯ during preview, and I don't have access to the "nightly" VS builds. I've tried to set the SDK via a global.json
to 8.0.300, but that's not working.
@BethMassi ... In a couple of hours, I wasn't able to either get an 8.0 app based on the MAUI tutorial or using the sample app up and running. Even if the blocking errors could be resolved for either approach, the NRT static analysis is throwing a fit all over the place with the code provided. There's no AppShell.xaml
file, so I wonder now if we missed a tutorial update at 8.0's release. I'll proceed with the links, but I'll need to circle around to additional roles coverage later after I get a working auth-enabled MAUI app running. I'll try again next week with this.
Appreciate all the updates so far. It was definitely quite a challenge to get Blazor Hybrid auth to work on my end.
I have a lot going on currently but if I can get to it, I will remake a sample app in my own time and show you how I have it working. Maybe it will give you some ideas.
I've had trouble in prior years with preview VS and preview SDK. I'm documenting 9.0 via the preview SDK these days. Sometimes, my problems here are related to my VS breaking during a transition to a new framework, not the project. However, having the sample app and guidance at 7.0 can be problematic when I'm basing my test app on 8.0, and having NRTs blowing up all over the place isn't helpful either. One thing I might do on my next attempt is go back to the command line (dotnet
commands), which avoid VS troubles.
Yes, if you put up a repro app, I'll pull that down and see if it will compile here. I hope to come back to this issue sometime next week.
@guardrex I can take a look at this next week as well. I don't have an Entra tenant at the moment to test.
I managed to get the sample app running π.
However, I'm now stuck on the guidance to place a non-standard entry into the Redirect URLs.
msal{APP ID}://auth
What?! That's not a valid URL. The Azure portal doesn't like it.
Oh, I see! It's a mobile/desktop thing ...
Mobile and Desktop applications option
Ok ... this what happens when you get a web dev in here π€£.
Working now! I can take it forward into some roles testing. I'll pick back up with this on Monday. Still tho ... the code is ... mmmmmm ... how can I put it without offending anyone??? ... π€ ... the code is ....... very interesting! π
I set up User
and Admin
roles and assigned the Admin
role to a user. When adding the claim type, I can see that the roles
claim arrives when a user is given a role in Entra. So far, so good!
I think on Monday I'm going to flip back over to the Maui-Blazor app because this auth example has no Blazor in it. I should be able to get the tutorial app up and running with auth now that I can see this auth app working here ... and then I'll take a stab at getting the auth rolled in.
... and the code provided isn't going to fly for multiple roles (or groups
/wids
for that matter to cover Azure security groups and built-in roles).
The code is ...
var roleClaim = token.Claims.FirstOrDefault(c => c.Type == "roles")?.Value;
if (!string.IsNullOrEmpty(roleClaim))
{
// If the role claim exists, add it to the IdTokenClaims
IdTokenClaims = new List<string> { roleClaim };
}
Here's the user with User
and Admin
roles, a wids
claim (b0f54661-2d74-4c50-afa3-1ec803f12efe
) for the Entra built-in "Billing Administrator" role assignment, and a groups
claim for an O365 security group that I created (173a9880-af52-47e7-b549-5fd5cd84e030
). I don't recall off the top of my head what the other groups
and wids
claims are, but I think I can look them up.
@BethMassi ... I'll suggest some better code than that when I flesh out the Blazor bits, hopefully on Monday.
Ideally, the code will show how to capture ALL of the roles
claims, groups
claims, and wids
claims that arrive with some cross-links (or text) on getting the extra claims to come down to the app (btw in case anyone isn't aware, it's via setting "groupMembershipClaims": "All"
in the app's manifest). The GUID of any security group is displayed out in the open in the Azure portal as soon as you create the group. Entra's built-in roles' GUID values are here :point_right: https://learn.microsoft.com/en-us/entra/identity/role-based-access-control/permissions-reference. When I get the app roles, groups, and Entra roles assigned to the claims identity, the <AuthorizeView>
should light up in Blazor. π€ππ
Here's the answer on one, so we'll want to hold on to this to add an explanation of what it is ... and I'd like to add a remark on it to the Blazor WASM article, which covers a lot of this stuff ...
I can't find out what the groups
GUID 69ff516a-b57d-4697-a429-9de4af7b5609
is. We need to get an π Azure/Entra god π to find out what that represents. I think it's another Azure/Entra internal type of thing not germane to the coverage really. Ultimiately, devs are going to create auth policies out of these GUIDs, and they only need to know the GUIDs for the built-in roles (via that table) and the security/distribution groups (via what the Azure portal tells them when they create the group).
UPDATE (8/1): I was sidetracked for a few days, but I hope to get back to this tomorrow (Friday).
[EDIT by guardrex to add code fencing to a tag]
The code is ...
var roleClaim = token.Claims.FirstOrDefault(c => c.Type == "roles")?.Value; if (!string.IsNullOrEmpty(roleClaim)) { // If the role claim exists, add it to the IdTokenClaims IdTokenClaims = new List<string> { roleClaim }; }
@guardrex Hey thanks a lot for all the work. I'm just low on personal time for this but still have some time to look at it at work.
In the code I quoted, I wonder have you figured out how to set the default role claim for roles? The <Authorize>
and [Authorize] have a Roles property, and UserPrincipal has an IsInRole extension method.
I suspect the reason is because the claim name it checks is http://schemas.microsoft.com/ws/2008/06/identity/claims/role, while the claim name sent to the app is, as you know, roles.
I haven't made it back here yet. Items came up overnight that I needed to address today.
figured out how to set the default role claim for roles
I don't think that's going to matter because the role claims are already using a type name of "roles" looking at my earlier researchβοΈ. I have "roles," "groups," and "wids" on the Hybrid side. AFAICT at this point, the challenge is getting the Blazor app (BlazorWebView
/auth state provider) to receive the claims. I'll try to get back to this issue for further research as soon as I can ... I hope on Monday.
Made it back for another look π .
@LapinskasL ... UPDATED: I can't get an IAccount
established with the code that you provided. I don't think I should spend much time with it because ........................
@BethMassi ... This issue is likely going to require a PU-provided sample for doc updates, and I assume it would be based on the Hybrid-BWA sample. Even if @LapinskasL's approach based on the (incomplete†) docs is correct, the PU usually makes specific choices about what they want to show/explain that probably aren't going to exactly match what @LapinskasL has.
incomplete†: @LapinskasL did well getting as far as he did with this content. Quite a lot is left out from looking at the code he posted relative to the article. I can fix the article based on what you/they want to show.
I understand that you'll be OOF soon, so I'll wait until you return if you want to address this later.
@guardrex sorry for the delay! I haven't been able to look at this. Adding @JeremyLikness to this thread to see if he has any suggestions while I'm OOF.
@guardrex I updated that reddit post of mine with more new code. It seems I needed a few changes to the Routes.razor file to make the [Authorize] attribute and <AuthorizeView>
, <Authorized>
, <NotAuthorized>
tags work.
The Roles attributes for the attribute and tags still don't function though, but I can use policies in the views which makes the code cleaner.
I'm punting it to the product unit for resolution because I couldn't get the guidance to work myself.
BTW ... You must code-fence markup :point_up: to get it to show up in GH comments.
I'm not sure what you're asking me to do in the last sentence.
Use backticks around inline code to get tags to show up in GH comments. I'll edit your post :point_up: to add them.
See discussion π https://github.com/dotnet/AspNetCore.Docs/issues/33851#issuecomment-2417016350
UPDATE (10/24) π£ ... I failed in my attempt to get Entra auth (MSAL) integrated into the MauiBlazorWeb app π’. I was stopped cold by this problem and just couldn't get the πππ resolved in spite of using latest packages (Microsoft.Identity.Client
v4.66.1). A member of engineering with more experience and intelligence π§ will need to provide the sample, and then I can write content based on its configuration. We've been chatting about this offline. I don't have an ETA yet for the new sample, but I'll remark here (or Beth will) when there's new information.
Description
I've been having severe trouble implementing authentication and authorization in Blazor Hybrid apps.
While the guide has a lot of code, I'm not quite sure how to properly integrate Entra ID into it. I find myself left with a lot of questions.
"What will happen when the token expires?" "Is it automatically renewed when it expires?" "How do I reduce token expiration time so I can test it?" "Why is the AuthorizeView tag working, but not its Roles attribute?" "Why is the [Authorize] attribute not working?"
It would help if the docs used implementation with Entra ID (or provide a sample with it) and also addressed those questions. Coming from the MVC framework, I can't help but feel like there's missing features and the answers to these questions are hard to find.
I've made a post on reddit too if you want to see how far I got: https://www.reddit.com/r/dotnet/comments/1e05wel/how_to_fully_integrate_entra_id_authorization/
Page URL
https://learn.microsoft.com/en-us/aspnet/core/blazor/hybrid/security/?view=aspnetcore-8.0&pivots=maui
Content source URL
https://github.com/dotnet/AspNetCore.Docs/blob/main/aspnetcore/blazor/hybrid/security/index.md
Document ID
cb3ca917-28cc-126f-a7ff-3ff00ad30677
Article author
@guardrex