3

I have created a custom ApiAuthenticationStateProvider that after returning an AuthenticationState is still stating

info: Microsoft.AspNetCore.Authorization.DefaultAuthorizationService[2]
      Authorization failed.

Here is a simplified version of my ApiAuthenticationStateProvider that is failing:

public class ApiAuthenticationStateProvider : AuthenticationStateProvider
{
   public override Task<AuthenticationState> GetAuthenticationStateAsync()
   {
       Console.WriteLine("Getting auth state...");
               
       var claims = new[] { new Claim(ClaimTypes.Name, "some.email@somewhere.com") };
       var authenticatedUser = new ClaimsPrincipal(new ClaimsIdentity(claims));
       var authState = Task.FromResult(new AuthenticationState(authenticatedUser));

       return Task.FromResult(authState);
   }
}

I can tell from the Console.WriteLine that is using my custom provider but to provide full details, here is the code i used to add that in Program.cs:

builder.Services.AddScoped<AuthenticationStateProvider, ApiAuthenticationStateProvider>();

weeksdev
  • 4,265
  • 21
  • 36

3 Answers3

3

The issue can be resolved in this answer. https://stackoverflow.com/a/20254797/2682662

Basically when constructing the ClaimsIdentity you need to provide a string value for the authentication type.

var authenticatedUser = new ClaimsPrincipal(new ClaimsIdentity(claims, "Needs Auth Type Here"));
Niederee
  • 4,155
  • 25
  • 38
  • this answer appears to be most correct and links to an explanation of why the string 'auth type' is needed. – kltft Jul 08 '20 at 15:23
2

For this to work on Blazor you will have to add authenticationType parameter value with ClaimsIdentity so your code will be changed to:

public class ApiAuthenticationStateProvider : AuthenticationStateProvider
{
   public override Task<AuthenticationState> GetAuthenticationStateAsync()
   {
       Console.WriteLine("Getting auth state...");
               
       var claims = new[] { new Claim(ClaimTypes.Name, "some.email@somewhere.com") };
       var authenticatedUser = new ClaimsPrincipal(new ClaimsIdentity(claims, AuthenticationTypes.Password));
       var authState = Task.FromResult(new AuthenticationState(authenticatedUser));

       return Task.FromResult(authState);
   }
}

Notice the AuthenticationTypes.Password parameter for ClaimsIdentity.

This should be same in all places where ClaimsIdentity is constructed.

Update: As per this comment, the value of authentication type should be one of the values defined in AuthenticationTypes class. Updated the above code to use this class instead of a random auth type name.

Umair
  • 4,864
  • 3
  • 28
  • 47
1

https://learn.microsoft.com/en-us/dotnet/api/system.security.claims.claimsidentity.-ctor?view=netcore-3.1

your ClaimsIdentity() object instantiated with just the array of claims you create above appears correct in the documenation but providing a string of claim type (also in the documenation above) seems to actually be what is required

var authenticatedUser = new ClaimsPrincipal(new ClaimsIdentity(claims, "Needs Auth Type Here"));

weeksdev
  • 4,265
  • 21
  • 36
kltft
  • 3,173
  • 2
  • 14
  • 18