I have a .NET 8 server-side Blazor app. It uses Entra ID for authentication and I've created a CustomAuthenticationStateProvider that gets roles from a database.
public class CustomAuthenticationStateProvider : AuthenticationStateProvider{ private readonly IHttpContextAccessor _httpContextAccessor; private readonly IDBAccess _roleService; // Custom service to fetch roles from the database private IMemoryCache _cache; public CustomAuthenticationStateProvider(IHttpContextAccessor httpContextAccessor, IDBAccess roleService, IMemoryCache cache) { _httpContextAccessor = httpContextAccessor; _roleService = roleService; _cache = cache; } public override async Task<AuthenticationState> GetAuthenticationStateAsync() { var user = _httpContextAccessor.HttpContext?.User; AuthenticationState retval = new AuthenticationState(user ?? new ClaimsPrincipal(new ClaimsIdentity())); if (user.Identity.IsAuthenticated) { _cache.TryGetValue("principal", out ClaimsPrincipal principal); var newUser = principal; if (principal == null) { // Fetch additional roles from the database var username = user.Identity.Name; // Get user's name var dbuser = await _roleService.GetUserByName(username); if (dbuser != null) { // Add the custom roles to a new ClaimsIdentity var claims = new List<Claim>(user.Claims); claims.Add(new Claim(ClaimTypes.Role, dbuser.Role)); var identity = new ClaimsIdentity(claims, user.Identity.AuthenticationType); newUser = new ClaimsPrincipal(identity); _cache.Set("principal", newUser); retval = new AuthenticationState(newUser); } } else { retval = new AuthenticationState(newUser); } } return retval; }}It seems to work fine, it fetches the roles from the db and adds it to the ClaimsPrincipal before returning it in the AuthenticationState.
As soon as I add @attribute [Authorize(Roles = "Admin")] to my page however, I get an "Access Denied" error. If I remove the Authorize attribute, and look for the role using IsInRole in the code, it finds it no problem.
What am I missing?