I am trying to implement "role-based authorization" using IdentityServer4 to provide access to my user-role-based API.
For example, I want to have two roles for the user, that is, FreeUser and PaidUser, and I want to provide access to the API through the authorization attribute using [Authorize (Roles = "FreeUser")), please help me how can I achieve this.
I have the following solution structure:
- IdentityServer
- Webapi
- Javascript client
I registered my Javascript client as follows:
new Client { ClientId = "js", ClientName = "javascript client", AllowedGrantTypes = GrantTypes.Implicit, AllowAccessTokensViaBrowser= true, RedirectUris = {"http://localhost:5004/callback.html"}, PostLogoutRedirectUris = {"http://localhost:5004/index.html"}, AllowedCorsOrigins = {"http://localhost:5004"}, AllowedScopes = { StandardScopes.OpenId.Name, StandardScopes.Profile.Name, "api1", "role", StandardScopes.AllClaims.Name } }
Sights
return new List<Scope> { StandardScopes.OpenId, StandardScopes.Profile, new Scope { Name = "api1", Description = "My API" }, new Scope { Enabled = true, Name = "role", DisplayName = "Role(s)", Description = "roles of user", Type = ScopeType.Identity, Claims = new List<ScopeClaim> { new ScopeClaim("role",false) } }, StandardScopes.AllClaims };
Users
return new List<InMemoryUser> { new InMemoryUser { Subject = "1", Username = "alice", Password = "password", Claims = new List<Claim> { new Claim("name", "Alice"), new Claim("website", "https://alice.com"), new Claim("role","FreeUser") } }, new InMemoryUser { Subject = "2", Username = "bob", Password = "password", Claims = new List<Claim> { new Claim("name", "Bob"), new Claim("website", "https://bob.com"), new Claim("role","PaidUser") } } };
WebApi Startup.cs
public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory) { loggerFactory.AddConsole(Configuration.GetSection("Logging")); loggerFactory.AddDebug(); JwtSecurityTokenHandler.DefaultInboundClaimTypeMap.Clear(); app.UseCors("default"); app.UseIdentityServerAuthentication(new IdentityServerAuthenticationOptions { Authority = "http://localhost:5000", ScopeName = "api1", // AdditionalScopes = new List<string> { "openid","profile", "role" }, RequireHttpsMetadata = false }); app.UseMvc(); }
Web api controller
namespace Api.Controllers { [Route("[controller]")] public class IdentityController : ControllerBase { [HttpGet] [Authorize(Roles = "PaidUser")] public IActionResult Get() { return new JsonResult(from c in User.Claims select new { c.Type, c.Value }); } [Authorize(Roles = "FreeUser")] [HttpGet] [Route("getfree")] public IActionResult GetFreeUser() { return new JsonResult(from c in User.Claims select new { c.Type, c.Value }); } } }
Javascript Client app.js Here I am trying to log into the user system through IdentityServer and make an API request.
var mgr = new Oidc.UserManager(config); mgr.getUser().then(function (user) { if (user) { log("User logged in", user.profile); } else { log("User is not logged in."); } }); function login() { mgr.signinRedirect(); } function api() { mgr.getUser().then(function (user) { var url = "http://localhost:5001/identity/getfree"; var xhr = new XMLHttpRequest(); xhr.open("GET", url); xhr.onload = function () { log(xhr.status, JSON.parse(xhr.responseText)); }; xhr.setRequestHeader("Authorization", "Bearer " + user.access_token); xhr.send(); }); } function logout() { mgr.signoutRedirect(); }
The input stream is working fine, and I can log in successfully, and I can get the role in the access token.

When I make a request in the API by clicking the (Call Api) button, I get the following error. 