Secure Your .NET 5 Blazor Server App with MFA

Blazor is an exciting new technology from Microsoft that will allow developers to bring C# to clients. Server and client components are written in the same language and can be used and re-used interchangeably. Blazor comes in two flavors, server and client apps. In this tutorial you will be working with Server Blazor apps, where the C# code is run on the server, and messages are exchanged using SignalR.


This is a companion discussion topic for the original entry at https://developer.okta.com/blog/2022/01/07/blazor-server-side-mfa

I’m doing WASM 6.0.1 and I see my razor pages will honor a policy name like this…
@attribute [Authorize(Policy = "SomePolicyName")]

when I have a simple policy like this…

	options.AddPolicy("IsTrue", policy => policy
		.RequireAssertion(_ => true)
	);

And yet this fails…

	options.AddPolicy("IsJohnDoe", policy => policy
		.RequireUserName("John.Doe@Company.com")
	);

Instead I have to write something like this…

	options.AddPolicy("IsJohnDoe", policy => policy
		.RequireAssertion(_ =>
		{
			var username = _.User.Claims.SingleOrDefault(_ => _.Type == "preferred_username")?.Value;
			return "John.Doe@Company.com".Equals(username, StringComparison.OrdinalIgnoreCase);
		})
	);

And while this works…

	options.AddPolicy("HasGroups", policy => policy
		.RequireClaim("MyGroupArray")
	);

this will fail…

	options.AddPolicy("HasGroup1", policy => policy
		.RequireClaim("MyGroupArray", "Group1")
	);

and so I do this…

	options.AddPolicy("HasGroup1", policy => policy
		.CustomRequireClaim("MyGroupArray", "Group1")
	);

with this extension method…

	public static class CustomAuthorizationPolicyBuilder
	{
		static Func<Microsoft.AspNetCore.Authorization.AuthorizationHandlerContext, string, string[], bool> _CustomRequireClaim
			= (ctx, claimName, allowedValues) => {
				var jsonArray = ctx.User.Claims.SingleOrDefault(_ => _.Type == claimName).Value;
				var userValues = JsonSerializer.Deserialize<string[]>(jsonArray).ToHashSet<string>(StringComparer.OrdinalIgnoreCase);
				return allowedValues.Any(allowedValue => userValues.Contains(allowedValue));
			};

		public static Microsoft.AspNetCore.Authorization.AuthorizationPolicyBuilder CustomRequireClaim(
			this Microsoft.AspNetCore.Authorization.AuthorizationPolicyBuilder me,
			string claimName,
			params string[] allowedValues
		)
			=> me.RequireAssertion(ctx => _CustomRequireClaim(ctx, claimName, allowedValues));
	}

I didn’t have any of these challenges while securing WebAPI endpoints with policies.
Perhaps I should have installed the Okta.AspNetCore nuget package in my WASM project (I have that in my WebAPI)?

Under the Access section click on Multifactor Settings. For this application you will only be enabling SMS Authentication but you can see the Factor Types that Okta allows on this page. Under the SMS Authentication tab set the drop-down to Active.

Sorry i can’t find these options