IdentityServer4 with ASP.NET Identity and client credentials flow

154 views Asked by At

I have IdentityServer4 (IDS4) working with multiple apps (Blazor WASM, ASP.NET Core API) using authorization_code. I'm using ASP.NET Identity for all apps.

I added one more API controller to Identityserver4 app (Controllers/Api/AccountController) and added one client for client_credentials flow. Purpose of this client is to access AccountController from API projects with authorization.

When I call IDS/api/Account/Register, it redirects to login page. Without [Authorize] attribute, it works fine.

How can I configure authorization for a client_credentials flow client?

Here are my IDS configs:

var services = builder.Services;
var configuration = builder.Configuration;

services.Configure<CookiePolicyOptions>(options =>
            {
                // This lambda determines whether user consent for non-essential cookies is needed for a given request.
                //options.CheckConsentNeeded = context => true;
                options.MinimumSameSitePolicy = SameSiteMode.Lax;
            });

builder.Services.AddControllersWithViews()
                .AddSessionStateTempDataProvider()
                .AddRazorPagesOptions(options => 
                {
                    //options.AllowAreas = true;
                    //options.Conventions.AuthorizeAreaFolder("Identity", "/Account/Manage");
                });
            
var connectionString = configuration.GetConnectionString("MSSQLConnection");
var applicationName = builder.Environment.ApplicationName;

services.AddDbContext<AppDbContext>(builder => builder.UseSqlServer(connectionString, 
                options => options.MigrationsAssembly(applicationName)));

services.AddIdentity<ApplicationUser, IdentityRole>()
                .AddEntityFrameworkStores<AppDbContext>()
                .AddDefaultTokenProviders();
                //.AddDefaultUI();

services.AddLogging(options =>
            {
                options.AddConsole();
            });

services.Configure<ForwardedHeadersOptions>(options =>
            {
                options.ForwardedHeaders = ForwardedHeaders.XForwardedFor | ForwardedHeaders.XForwardedProto;
            });

// ..or configures IIS out-of-proc settings
services.Configure<IISOptions>(iis =>
            {
                iis.AuthenticationDisplayName = "Windows";
                iis.AutomaticAuthentication = false;
            });

// ..or configures IIS in-proc settings
services.Configure<IISServerOptions>(iis =>
            {
                iis.AuthenticationDisplayName = "Windows";
                iis.AutomaticAuthentication = false;
            });

services.AddIdentityServer(options =>
            {
                options.Events.RaiseErrorEvents = true;
                options.Events.RaiseFailureEvents = true;
                options.Events.RaiseInformationEvents = true;
                options.Events.RaiseSuccessEvents = true;
                options.Discovery.ShowIdentityScopes = false;
                options.Discovery.ShowApiScopes = false;
                options.Discovery.ShowClaims = false;
                options.Discovery.ShowExtensionGrantTypes = false;

                options.UserInteraction.LoginUrl = "/Account/Login";
                options.UserInteraction.LogoutUrl = "/Account/Logout";

                options.Authentication = new IdentityServer4.Configuration.AuthenticationOptions()
                {
                    CookieLifetime = TimeSpan.FromHours(10), // ID server cookie timeout set to 10 hours
                    CookieSlidingExpiration = true
                };
            })
            .AddOperationalStore(options => options.ConfigureDbContext = builder =>
                builder.UseSqlServer(connectionString, options => options.MigrationsAssembly(applicationName)))
            .AddConfigurationStore(options => options.ConfigureDbContext = builder =>
                builder.UseSqlServer(connectionString, options => options.MigrationsAssembly(applicationName)))
            .AddAspNetIdentity<ApplicationUser>()
            .AddInMemoryCaching()
            .AddResourceOwnerValidator<ResourceOwnerPasswordValidatorService>()
            .AddSigningCredential(certificate);

services.AddAuthentication();
services.AddLocalApiAuthentication();

services.AddAuthorization(options =>
            {
                options.AddPolicy(Roles.Admin,
                    policy => policy.RequireClaim(JwtClaimTypes.Role, Roles.GetRoleName(UserRole.Admin)));

                options.AddPolicy(Roles.SuperAdmin, policy =>
                    policy.RequireAssertion(context =>
                    context.User.HasClaim(JwtClaimTypes.Role, Roles.SuperAdmin) || context.User.HasClaim(JwtClaimTypes.Role, Roles.Admin)));
            });

            services.AddSession(options => {
                options.IdleTimeout = TimeSpan.FromMinutes(10);
            });

Update (Resolution) Finally resolved using Bearer AuthenticationScheme support to IDS for Api Endpoints

In Program.cs

services.AddAuthentication(IdentityServerAuthenticationDefaults.AuthenticationScheme)
         .AddIdentityServerAuthentication(options =>
         {
               options.Authority = IdentityServerUtility.Authority;
               options.ApiName = "IDS_API";
         });

In Controller Authorization including policy works fine.

[Route("api/[controller]")]
[ApiController]
[Authorize(AuthenticationSchemes = IdentityServerAuthenticationDefaults.AuthenticationScheme)]
public class AccountController : ControllerBase
{
   [Authorize(Policy=Roles.Admin)]
   [HttpPost("Register")]
   public async Task<AppActionResult> Register([FromBody] UserDto model)
   {
      //...
   }
}

Thank you.

0

There are 0 answers