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,127
  • 19
  • 35

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
  • 3,955
  • 24
  • 37
  • 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
  • 3,322
  • 2
  • 22
  • 38
1

https://docs.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,127
  • 19
  • 35
kltft
  • 583
  • 5
  • 13