0

I need to know the client's grant type (or OAuth Flow type) in my API protected by IdentitySrever4, but not sure how to do that. I am assuming that I need to add the grant type to the access token. Can someone help me by pointing me to instructions/documentations or sample code?

UPDATE

Under standard IdentityServer4 EF model, my SQL Server data store has a ClientGrantTypes table and a ClientClaims table (see screenshot below). I am assuming that I need to create a ClientClaims record that ties into ClientGrantTypes. If it is SQL, you can just join the tables on ClientID, but how do you implement it here to get the Grant Type into access token?

enter image description here

Alexu
  • 1,015
  • 2
  • 12
  • 32

2 Answers2

1

It would be easier to find the answer if you explained the purpose for the requirement.
From my experience one common task is to distinguish authorization_code and client_credentials flow use for the same client, but that's easy: the second one does not contain user information (sub and sid claims).
Also don't forget about restricted auth flow combinations in Identityserver (for instance you can't allow both implicit and authorization_code flow for the same client), so one client is usually bound to the only user interactive flow.
Finally, the auth flow is generally not about API. It's only about interaction among IdP and Client. API usually use scopes as general information about clients, so... when you have two clients -- one with implicit grant and the other with authorization_code, you can distinguish which one is in use by setting different scopes.
Isn't that enough?

A check for a particular grant type could be performed in Identityserver the following way:

public class ExtendedClaimsService : DefaultClaimsService{
    public override async Task<IEnumerable<Claim>> GetAccessTokenClaimsAsync(
            ClaimsPrincipal subject,
            ResourceValidationResult resourceResult,
            ValidatedRequest request)
    {
        var outputClaims = (await base.GetAccessTokenClaimsAsync(subject, resourceResult, request)).ToList();

        //if (request.Secret.Type == "NoSecret") //this is more or less the same
        if ((request as ValidatedTokenRequest)?.GrantType != "client_credentials")
            {
                //filter out server-side-only scopes here
                //or add any custom claim you like
            }

        return outputClaims;
    }
}

Registration: services.AddTransient<IClaimsService, ExtendedClaimsService>(); after services.AddIdentityServer() in your Startup

d_f
  • 4,599
  • 2
  • 23
  • 34
  • Yes, you are right in that what I am trying to do here is to distinguish between authorization_code and client_credentials flows. And yes, what I am doing now is by testing the existence of user id. If that's the standard way, or at least a reliable way to do it, then I guess I am OK. I have been considering that as a workaround, not a solution. That's why I was looking for ways to add grant type as a claim. – Alexu Dec 21 '21 at 15:41
  • that is indeed reliable as the claimsset is signed by the IdP, so a user can't just remove the sub claim to gain more access. what I am thinking about right now is to perform such check on identityserver side to make requesting some ".service" scopes absolutely impossible without service creds (even the scope is allowed for the client). – d_f Dec 21 '21 at 15:53
  • one limitation can occur when you use custom "delegation" flow -- client creds with user info inside. if you do use delegation, you definitely need a separate "trusted-client" claim, but most likely you do not : ) – d_f Dec 21 '21 at 16:04
  • @Alexu, just updated the answer with a piece of code. Don't hesitate to vote up : ) – d_f Dec 21 '21 at 17:53
  • 1
    I did. Thank you very much. – Alexu Dec 21 '21 at 19:23
0

One option is to have different client definitions for the different flows and then use a ClientClaim to indicate what type of client it is:

To set the client claims in the client definition just set it like:

ClientClaimsPrefix="",

AlwaysSendClientClaims=true,

Claims = new List<ClientClaim>()
{
    new ClientClaim("role","admin"),
    new ClientClaim("name","joe"),
    new ClientClaim("admin","yes"),
    new ClientClaim("employmentid","employee"),
    new ClientClaim("employeetype","yes"),
    new ClientClaim("creditlimit","100000")
}

             
Tore Nestenius
  • 16,431
  • 5
  • 30
  • 40