Always Linter your API Definitions

An API definition may be thought of as an electronic equivalent of a receptionist for an organisation. A receptionist is normally the first person they see when visiting an organisation and their duties may include answering enquires about products and services.

This is similar to an API definition, when someone wants to do business electronically, they would use the API definition to obtain information about the available services and operations.

My thoughts are, API’s should be built customer first and developer second. Meaning an API needs to be treated as a product and to make it appealing to a consumer, it needs to be designed as intuitive and usable with very little effort.

Having standardised API definition documents across all your API’s, allows a consumer to easily navigate around your API’s as they will all have a consistent look and feel about them. This specially holds true when there are multiple teams developing Microservices for your organisation. You don’t want your consumers think they are dealing with several different organisations because they all look and behave differently. Also, when generating the client object models from several different API definitions from the same organisation, you want the property names to all follow the same naming conventions.

To ensure uniformity across all API schema definitions, a linter tool should be implemented. One such open-source tool is Spectral https://github.com/stoplightio/spectral from Stoplight, however there are many other similar products available.

Ideally the validation should be added as a task to your CI/CD pipelines when committing the changes to your API definition repository.

Using Spectral in MS DevOps API Projects

Spectral provides the capability to develop custom rules as a yaml or json file. I typically create a separate DevOps project to store these rules inside a repository which may be shared across other API projects.

Below is how I have setup the repositories section in the pipeline to include the linter rules and the API definition.

image

After downloading the Spectral npm package in the pipeline, I then run the CLI command to start the linter on the schema specification document which is normally stored in a folder called ‘specification’ in the corresponding API repository.

clip_image001

An example of the pipeline job can be seen below. Here the job failed due to some rule violations.

clip_image002

The build pipeline and sample rules can be found here https://github.com/connectedcircuits/devops-api-linter

Hope this article now persuades you to start using Linter across all your API definitions.

Enjoy…

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…