0

I have correctly configured identity server 4 which authorizes a web api for method access. However, I cannot use the roles in the web api, the role is in the token but when it arrives on the web api it does not give me authorization to enter the api.

IDS4 Configuration

    new Client
                    {
                        ClientId = "spaclient",
                        ClientName = "SPA Client",
                        RequireConsent = false,
                        AllowedGrantTypes =  GrantTypes.ResourceOwnerPassword,
                        RequirePkce = true,
                        RequireClientSecret = false,
                        AllowAccessTokensViaBrowser = true,
                        AllowedScopes = new List<string>
                           {
                               IdentityServerConstants.StandardScopes.OpenId,
                               IdentityServerConstants.StandardScopes.Profile,
                               "role" 
                           }
                    }

 public static IEnumerable<ApiScope> ApiScopes =>
               new ApiScope[]
               {
              new ApiScope("spaclient", "SPA")
               };

            public static IEnumerable<ApiResource> ApiResources =>
              new ApiResource[]
              {
                new ApiResource("spaclient", "SPA")
              };

            public static IEnumerable<IdentityResource> IdentityResources =>
              new IdentityResource[]
              {
              new IdentityResources.OpenId(),
              new IdentityResources.Profile(),
               new IdentityResource("role","User Role", new List<string>() { "role" })
              };

CLIENT CONFIG

JwtSecurityTokenHandler.DefaultInboundClaimTypeMap.Clear();
            builder.Services.AddAuthentication("Bearer")
                    .AddJwtBearer("Bearer", options =>
                    {
                        options.Authority = "https://localhost:9002";  // --> IdentityServer Project
                        options.RequireHttpsMetadata = true;
                        options.SaveToken = true;
                        options.TokenValidationParameters = new TokenValidationParameters
                        {
                            ValidateAudience = false,
                            NameClaimType = "role",
                            RoleClaimType = "role"
                        };
                    });

CONTROLLER PART

    [HttpGet]
    [Authorize(Roles ="Administrator")] // <-- with role not work
    public IEnumerable<string> Get()
    {
        return new string[] { "value1", "value2" };
    }



 [HttpGet]
        [Authorize]<-- without role work fine
        public IEnumerable<string> Get()
        {
            return new string[] { "value1", "value2" };
        }
Angelo
  • 101
  • 1
  • 9

1 Answers1

1

In your access token, there is no role claim. You need to configure your existing ApiScope or ApiResource to include the necessar role claim.

What you have done is to only include it in your ID-token.

see my answer here about the relationship between the various resource types in IdentityServer

To add a userclaim to your APIScope, like this:

new ApiScope(name: "spaclient",
displayName:"SPA",
userClaims: new List<string>{ "role" }),

Also, you must request the spaclient and openid scopes as well.

To control the token lifetimes:

var client2 = new Client
{
    ClientId = "authcodeflowclient", 
 
    IdentityTokenLifetime = 300,               //5 minutes
    AccessTokenLifetime = 3600,                //1 hour
    AuthorizationCodeLifetime = 300,           //5 minutes
    AbsoluteRefreshTokenLifetime = 2592000,    //30 days
    SlidingRefreshTokenLifetime = 1296000,     //15 days
    ...

To complement this answer, I write a blog post that goes into more detail about this topic: IdentityServer – IdentityResource vs. ApiResource vs. ApiScope

Tore Nestenius
  • 16,431
  • 5
  • 30
  • 40
  • If you login via MVC app the role works correctly so the piece of code you suggested is already present in the code, the problem is that the token I have to request in this case has no callbackurl but a simple token with GrantTypes = .ResourceOwnerPassword does not I know if I explained myself – Angelo Jan 07 '23 at 15:58
  • This is token get from login MVC after redirect, no role exist but it work with role!!! { "nbf": 1673107363, "exp": 1673107663, "iss": "https://localhost:9002", "aud": "WebAppMVC", "nonce": "638087040558572845.MGE5NDIyNjMtMTk4My00ODZlLWI1NGMtN2UxMjM3YjhmZDZkMDhlZDgzZmQtZDM3NS00ZWI3LTk5ZDQtMjVkMjlhMDg0YjJi", "iat": 1673107363, "at_hash": "H9scrHmtdJrRR8UeFaxI3A", "s_hash": "ETTlNk3AdlZLR85Y2N788w", "sid": "492EA1CDC3152278B09D8C07B9A544E8", "sub": "0f25aca2-c754-4de8-bd0c-66b79642a2ef", "auth_time": 1673107273, "idp": "local", "amr": [ "pwd" ] } – Angelo Jan 07 '23 at 16:05
  • The token you just added in the comment above is an ID-token, not an access token. These are two different tokens with different purposes; the ID-token is not meant to be sent to the API. – Tore Nestenius Jan 08 '23 at 12:06
  • You should try to avoid using ResourceOwnerPassword flow for modern applications. – Tore Nestenius Jan 08 '23 at 12:06
  • thx Nestenius, I understand what you're saying, but I need to authenticate through a generic client (android) or via javascript by simply providing the username and password with the client's id and then using the token received on microservices based on WEB API, the problem is that on the web application everything works correctly while on the web api it doesn't carry the roles, the other authentication methods don't work without a client secret, for this I have to use ResourceOwnerPassword, I don't and can't use any login interactions with the identity server via cellular, how do I solve it? – Angelo Jan 08 '23 at 13:29
  • Don't you get a separate access token back? or perhaps you don't ask for one? the ID-token can't be sent to the API (JWTBearer). About your problem, its hard to understand your specific archiecture. – Tore Nestenius Jan 08 '23 at 13:54
  • I have an ocelot gateway, behind the gateway I have created an IDS4 server and in the same server also asp authentication. net core identity to manage interactive login. then I have a web application written in MVC that uses interactive login hosted on the IDS4 server to be self-identified and therefore also uses user roles correctly – Angelo Jan 08 '23 at 15:14
  • Then I have a series of WEB API microservices that always have the [Authorize] and [Authorize(Roles = "...") tags, these microservices will be accessed via smartphones which first get a simple token via user and password and then via the token protected pages will receive, the problem is that I can't get it to work with roles. I hope I explained myself – Angelo Jan 08 '23 at 15:16
  • To keep your sanity, I recommend hosting IdentityServer on its own domain/service, because otherwise, it will be complicated/complex to reason about when it does not work. – Tore Nestenius Jan 08 '23 at 15:18
  • The problem is still that you confuse ID and access tokens. – Tore Nestenius Jan 08 '23 at 15:18
  • Yes ID is used by MVC web app with interactive login to get access to protected pages with role. Access token is used by SPA app to gain access to microservice WEB API role in this case is missing. – Angelo Jan 08 '23 at 15:48
  • But you can't use the ID token to access the API, only the access token can do that. Can you add both tokens to your question? The ID is only used to created the initial user cookie session – Tore Nestenius Jan 08 '23 at 16:25
  • I have two clients configured on IDS4, the first for the MVC web application and the second configured to use only the received token on Web API based microservices. in the second everything works great even for the methods that have the [Authotize] tab set , it's the roles that don't work and I need to find a way to tell the asp .net core identity residing on the IDS4 server to include it or the client using the BEARER Token to read it. – Angelo Jan 08 '23 at 17:10
  • As I said in my answer, you need to create an ApiScope and ask for that scope, to get the role claim into the access token – Tore Nestenius Jan 08 '23 at 17:21
  • i did that but its not working, i also tried to include on the microservice besides the AddJwtBearer also AddOpenIdConnect and AddCookie . n the client configuration on the IDS4 server I also included new ApiScope(name: "spaclient", displayName:"SPA", userClaims: new List{ "role" }) – Angelo Jan 08 '23 at 17:42
  • Your best option now is to update your question with the latest code... bit to hard to not have the full picture – Tore Nestenius Jan 08 '23 at 18:24
  • the posted code is the correct one, you only need to add the part of the code you suggested then it's complete. the rest are all evidence. I think its peculiarity is given by the fact that IDS4 implicitly uses asp.net core identity which is not a custom solution. – Angelo Jan 08 '23 at 21:35
  • ID4, does not depend or require ASP.NET Identity, but using parts of it may be benefitial. – Tore Nestenius Jan 09 '23 at 07:59
  • when I request the token on IDS4 with username and password by setting the client with GrantTypes.ResourceOwnerPassword it doesn't add the roles in fact the generated token has no roles, maybe I have to implement an override on the server to add the roles too but I don't know how and where to do it – Angelo Jan 09 '23 at 08:20
  • Now Work! Finally I Found the problem. it was necessary to add the part of the code that you had indicated to me, the problem is that I had left this line commented out "JwtSecurityTokenHandler.DefaultInboundClaimTypeMap.Clear();" this is essential otherwise it won't work – Angelo Jan 09 '23 at 09:54
  • as a hint, as it says here: "While technically you could share the ASP.NET Core host between Duende IdentityServer, clients or APIs. We recommend putting your IdentityServer into a separate application. https://docs.duendesoftware.com/identityserver/v6/fundamentals/hosting/ – Tore Nestenius Jan 09 '23 at 10:05
  • Tore Nestenius Could you by any chance help me on this as well? https://stackoverflow.com/questions/75150018/indentity-server-4-behind-a-ocelot-gateway – Angelo Jan 18 '23 at 08:22