Setting up custom Claims for an API registered in Azure AD

One way to further reduce the surface area attack on an API when using the Client Credential OAuth flow is to pass claims in the token. This adds another layer of security and provides more granular control over your API. By adding custom claims within the token, the API can inspect these and restrict what operations the client may perform within the API service. This may be just to limit basic crud type operations or some other type of grant requirement. More information about optional claims can be found here: https://docs.microsoft.com/en-us/azure/active-directory/develop/active-directory-optional-claims

Just to recall, Client Credentials flow is normally Client-to-Service requests and has no users involved in the flow. A Service Principal (SP) object is associated with the Client App when making calls to a backend service API. The value of this Id can be found under AAD Enterprise Applications and is the ObjectId  of the application name. To ensure the SP used to call your API is the one you are expecting, use the oid or sub claims to validate the SP as another security check.

Also the Client Credentials flow is meant to be used with confidential clients. These are clients that are running on the server as opposed to those running on user devices (which are often referred to as ‘public clients’) as they are able to store the secret securely. Confidential clients provide their client ID and client secret in the requests for access tokens.

 

Scenario

A typical scenario is where a Client App needs to call a backend API Service. Here the Client App is a CRM Website which is calling a CRM Service which is the backend API Service to either get a users profile or update their details using the Client Credentials flow. Also to limit operational functionality, two roles will be sent with the bearer token to allow only reading or updating the CRM contact information.

 

image

 

In this article I will go through the process of adding a list of Application claims to an App registered as an API service (CRM Service) in Azure Active Directory (AAD). Another App registration is also required for the client (CRM Website) which has a set of restricted claims. These restricted claims will be inserted into the Access token where the API service (CRM Service) would interrogate the claims and perform the required operations if the claims are valid.

 

Configuration Walkthrough

Below are the steps required to create an AAD App Registration for the CRM Service API and to add the required application claims (roles). The claims are added by modifying the manifest file after the App has been registered as there is no UI available to manage this.

 

Registering the Service API

1. Register the CRM Service API – Under the Azure Active Directory page, click on App registrations and New registration

 

clip_image001[7]

2. Add a name (CRM Service) for the application and then click the Register button at the bottom of the page.

 

image

 

3. Adding Claims – Once the App registration has been saved, click on the Manifest menu option to view and update the manifest appRoles via the portal.

 

image

 

Now we can add a of collection of custom roles under the “appRoles” attribute using the following JSON structure for the claims. This is where you define the complete list of custom roles that your API service will support. The claims I will be adding for the CRM service are basic crud type operations. Note the value for the id for each role is just a Guid to keep it unique within the tenant.

 

image

Remember to click the Save button to on the top to update the manifest.

 

4. Set Application ID URL – Under the Expose an API menu option, click the Set for Application ID URI. This value will be used as the Scope parameter when requesting an OAuth token for the Client App. You can also view this value from the app registration Overview page.

 

clip_image001[13]

 

That is all required to register the API Service and to add custom application claims. Next is registering the client. 

 

Registering the Client App

1. Create a new App registration as before, but for the client (CRM Website)

 

clip_image001[15]

 

2. Add the required permissions – This section is where you define the roles required for the client app. To add the permissions, click on API Permissions and then Add a permission.

clip_image001[17]

 

Then click on My API’s on the top menu to list all your registered apps. Select the CRM Service app which was added in the first section to which you want access to.

 

image

 

Select Application permissions and then expand the permissions. This will list all the available roles available that was added when registering the CRM Service API. For the CRM Website, I only require the read and update roles. Once checked, then click on the Add permissions button.

 

clip_image001[21]

 

Once the permissions have been added, Click on Grant admin consent for the cloud and then press Yes on the dialogue box.

 

clip_image001[23]

 

The status of the permissions should then be all green as highlighted below.

 

clip_image001[25]

 

5. Add a client secret – Click on the Certificates & secrets menu option to add a new client secret. Remember to take note of this value as it is required when obtaining an OAuth token later.

 

clip_image001[27]

 

Requesting an OAuth Token

Before the Client App (CRM Website) can call the API Service (CRM Service), a bearer token needs to be obtained from the OAuth 2.0 token endpoint of AAD. For this, I am going to use Postman to act as the Client App by sending the following parameters. You should be able to get all these values from the Overview of the Client App (CRM Website) and the Scope value from the API Service (CRM Service)

  • grant_type – Must be set to client_credentials
  • client_id – The application found in the Client App (CRM Website)
  • client_secret – The secret that was generated in the Client App (CRM Website) which must be URL encoded.
  • scope – This the application ID URL of the API Service (CRM Service) which must be URL encoded. Also you need to append /.default to the end of the URL eg  (scope=api://189f0961-ba0f-4a5e-93c1-7f71a10b1a13/.default)

 

Here is an example of the PostMan request to obtain the token. Remember to replace {your-tenant-id} with your one.

image

When you send it and all the parameters are correct, you should receive a JWT token as per below.

image

Now if you take the value of the “access_token” and use a tool like https://jwt.ms/ to decode it, you should see the custom application claims.

image

In conclusion, use custom claims to provide granular control of operations in your backend API’s and any security breaches from hijacked client applications. 

Keep a watch out for my next blog where I will show you how to access these claims from within an Azure Function.

Enjoy…

10 Replies to “Setting up custom Claims for an API registered in Azure AD”

  1. Thank Mahindra.

    I follow your post all the way through & get the same response.

    I saw quite a bit blogs about configuring the SCOPE while exposing the web api -> Grant permissions to the web API
    https://docs.microsoft.com/en-us/azure/active-directory-b2c/tutorial-web-api-dotnet?tabs=app-reg-ga

    What is the difference between configuring “SCOPE” & the “appRoles”.

    I am a bit confusing about the token for daemon client (services) & end user. Should I say I use “scope” for end users and “appRoles” for daemon client to control the permission for accessing web api?

    Looking forward to see more most from you.

  2. Hi Li,
    Yes, the two concepts can be quite confusing. Use appRoles for daemon services which do not involve a user and Scopes when an API is called on behalf of a user.
    Also when you adding a Scope to the API Service and then you add this permission to the Client App, its only available as Delegated permissions (signed-in user)

    Hope this helps.

    1. Hi Mahindra,

      The tutorial from the website assign the same scope value to all the signed in users, as a result they will have the same level permission when calling web api.

      Question:
      For Scopes option, is it possible to conditionally assign scope value to the token? e.g. if a user is in “Finance” department, then assign him “Api.Read” to the scope? In this way, I could consume the scope value in the down stream API controller as a way of authorization.

      If it is not feasible, what would be the alternative for authorization to give people different level of permissions with the help of azure active directory?

      Thanks
      Li

      1. Hi Li,
        You will need to define ‘User Application’ roles, then you assign the user to those roles from Enterprise applications page.
        Note there is a limitation where you can only assign a user to one role. If a user requires access to more roles, then you would use groups and assign the group to the role.

        Cheers Mahindra

    2. Hi Mahindra,

      I figure it how it works by using role based access control . What you did with this blog is associate a defined role with a application. Later when the application call the api, it will pass on the permission check since the application has the required role in the token.

      Same principle, 1) I define a rule like what you did but targeting users. 2) associate the role with either security group or user 3) web api check the role requires, it will let it in if the user token has the role. Otherwise not.

      If there is any other ways of doing the same thing. Please let me know…

      Thanks again. This has been puzzled me for a while. It suddenly makes sense now. I need to do a design and estimation for a project. Finally I am a bit more confident to present the sow.

      More posts please… I will be following you for hands on practice 🙂
      Li

      1. Hi Li, sounds like you have got it sorted. I would also verify the type of OAuth flow you require for your scenario. Also good luck on your design and let me know if you need any help.

        Cheers,
        Mahindra

  3. Hi Mahindra,

    is there a way to add custom claims to the token for a specific client, without using AppRoles?

    The reason is: We have a multiple services, but hundreds of different clients for daemon apps running at subsidiaries. Each has a set of attributes (subsidiary number, subsidiary location) etc, and we need some of them, especially the subsidary number, in the access token.

    It doesn’t really feel to be the correct approach to add hundreds of AppRoles (at least one for each subsidiary) to each service, and then add a permission for each client to that specific AppRole for the subsidiary on each of the services.

    Regards,

    Sebastian

  4. Hi Sebastian,
    From what I understand you require a more granular approach for the claims which as you stated will be difficult to maintain.
    Maybe another approach is to exchange the client token with an internal token which you maintain programmatically and has the extra claims your API requires.

    1. Hi Ashish,
      You won’t be able to achieve that using this approach, instead you will need to user to authenticate themselves against an authentication server such as AuthO to obtain an ID token.

Leave a Reply

Your email address will not be published. Required fields are marked *