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.