rene.klomp

Leveraging Access Token Claims in an API Process

Blog Post created by rene.klomp Employee on Mar 7, 2018

Whenever you create an API in Boomi, you have multiple options of securing the API through the means of authentication. First of all we have (Atom Controlled) 'Internal Authentication' which offers several options like Basic Authentication, Client Certificates and Custom Authentication through JAAS Modules. Furthermore, we have the option of using 'External Authentication' through an External Identity Provider allowing you to have the Identity Provider handling the authentication based on either SAML or OpenID Connect (OAuth).

 

Securing API's through External Authentication involves configuring an Authentication Source like Okta and also installing and configuring an Authentication Broker within API Management. How to build an API and setup External Authentication is beyond the scope of this article--for that, check out Getting Started with External Authentication for API Management .

 

Within API Management we can register and configure Applications. Users of API Management create Applications which serve to allow another entity, such as a business unit or third-party application, to access the API. The API Key that is generated for each authorized API is what allows the entity access to that particular API. For each Application that wants to use a particular API, the API Key has to be provided for each request. Authenticating the user using the application through e.g. OpenID Connect will be brokered to the Authentication Source for authentication. The Authentication Broker will issue and subsequently validate the Access Token also for each request. This whole flow is outlined in the Getting Started article linked above.

 

In the case of OpenID Connect also an ID Token is issued by the Authentication Broker. The main difference between the two type of tokens is:

  • The Access Token is a token that can be used by a client to access an API. Sending the token as an Authorization header with a request informs the API that the bearer of the token has been authorized to use the API. As such it is meant for authorizing the user to a resource server (API).
  • The ID Token is a token containing identity data. It is consumed by the client and is used to get user information like a user's name, email, etc., typically used for display in the UI. So the ID Token is meant for authenticating the user to the client and should not be used to obtain access to any resource (API) or make authorization decisions.

 

In this article we will explore how we can leverage the claims (statements about an entity) embedded in the Access Token to be used further down the linked API process, e.g. for taking decisions, transformations, masking, routing, etc.

 

The Access Token that is issued by the Authentication Broker is created as a JSON Web Token (JWT) and as said once a client has obtained this Access Token, it will include that token as a credential when making API requests in the form of an Authorization header using the Bearer schema. The content of the header might look like the following:

Authorization: Bearer eyJhbGciOiJSUzI1NiIsInR5cCIgOiAiSldUIiwia2lkIiA6ICJSU...<snip>...RQuTfPL7r_RhM_nND4x3x5u3QsAxuMtciqJ4z_ZVSYLHf1C_g

 

JWT's generally consist out of three Base64Url encoded parts, each separated by a '.' (period): a header, a payload, and a signature:

 

 

The header identifies which algorithm is used to generate the signature. An example header as issued by our Authentication Broker looks like this:

{
   "alg": "RS256",
   "typ": "JWT",
   "kid": "PMiuZZmryTRDlTbdLWuDlVExT57eDL_O9a61tWRLvdo"
}

 

What is more interesting in the lights of this article is the middle part or payload as the payload is containing the claims. As said before, claims are statements about an entity (e.g. the user using the application) and additional metadata. An example payload (as issued by our Authentication broker) looks like this:

{
   "jti": "b9bff6d0-eb80-4fe2-adda-a65b7aadd52d",
   "exp": 1519075018,
   "nbf": 0,
   "iat": 1519074718,
   "iss": "https://appserver.boomidemo.com:5443/auth/realms/6fcc0833-0ec2-4542-bc2c-4cd88286dfc8",
   "aud": "6fcc0833-0ec2-4542-bc2c-4cd88286dfc8:OPENID",
   "sub": "280c607e-f3b7-4d85-a0ff-f7ead94ff3be",
   "typ": "Bearer",
   "azp": "6fcc0833-0ec2-4542-bc2c-4cd88286dfc8:OPENID",
   "auth_time": 1519074692,
   "session_state": "96d80fec-cc22-418a-a6fa-481b28d80dca",
   "acr": "0",
   "client_session": "b64b031a-80e6-474c-b931-6e157601b1b1",
   "allowed-origins": [],
   "realm_access": {
      "roles": [
         "uma_authorization"
      ]
   },
   "resource_access": {
      "broker": {
         "roles": [
            "read-token"
         ]
      },
      "account": {
         "roles": [
            "manage-account",
            "manage-account-links",
            "view-profile"
         ]
      }
   },
   "address": {},
   "email_verified": false,
   "name": "Rene Klomp",
   "groups": [
      "Everyone",
      "Consultant"
   ],
   "preferred_username": "r...@dell.com",                                                            --- Hidden to prevent spam
   "identity_provider_alias": "Okta",
   "given_name": "Rene",
   "family_name": "Klomp"
}

 

In the token you can find a number of claims where the first seven are actually registered claims (according to RFC 7519 - JSON Web Token (JWT) ) such as:

{
   "jti": "b9bff6d0-eb80-4fe2-adda-a65b7aadd52d",                                                   --- JWT ID Claim
   "exp": 1519075018,                                                                               --- Expiration Time Claim
   "nbf": 0,                                                                                        --- Not Before Claim
   "iat": 1519074718,                                                                               --- Issued At Claim
   "iss": "https://appserver.boomidemo.com:5443/auth/realms/6fcc0833-0ec2-4542-bc2c-4cd88286dfc8",  --- Issuer Claim
   "aud": "6fcc0833-0ec2-4542-bc2c-4cd88286dfc8:OPENID",                                            --- Audience Claim
   "sub": "280c607e-f3b7-4d85-a0ff-f7ead94ff3be",                                                   --- Subject Claim
   ...

 

As an example, 'iat' stands for 'Issued At' and is giving the time at which the token was issued in NumericDate format which is "a JSON numeric value representing the number of seconds from 1970-01-01T00:00:00Z UTC until the specified UTC date/time, ignoring leap seconds - Ref. RFC 7519 - JSON Web Token (JWT) ".

So if you do the math for our example you can find that this particular token was issued at 2/19/2018, 4:11:58 PM EST.

 

Now we are more interested in the public claims like group memberships for the user as they are contained within this JWT. We have setup our External Identity Provider Okta to include all user attributes as defined on the app profile and the groups claim in our example case is filtered according to a regex filter to contain all groups (groups Regex .*):

 

 

As can be seen from the Okta Administration Console below the user is indeed in the 'Everyone' and the 'Consultant' group and this is nicely reflected in the groups claim that can be found in the Access Token above!

 

 

Having access to the Access Token and its embedded claims downstream in the linked API process opens up a whole new way of dynamic processing and decision taking. Now how do we get access to these claims in the API process?

 

First of all, to get access to the Access Token in the API process is by adding the 'Authorization' header to the list of 'Dynamic Document Property Headers' on the General API Configuration tab:

 

 

This way the Authorization header can be accessed in the underlying API process as the Dynamic Document Property (DDP) 'inheader_Authorization'. Now it is easy to extract the relevant claims embedded in this header representing our JWT access token either by using a Data Process shape with as a first step a regular expression to take out the payload and then a second BASE64 Decode step to decode into JSON...

 

 

...or as part of a Map shape where we can use a String Split...

 

...and 2 lines of Groovy script to BASE64 Decode our JWT...

 

 

In the sample service enabled process below that exposes patient information inside a database as a REST API I have made the testing for a groups claim containing 'Staff' very explicit as part of the first branch. Again, there are many ways you can implement this and this is just one way of doing so.

 

 

In the second branch we get the data for a certain patient based on a patient id that we send as a query parameter as part of the request and we do the transformation into JSON to return in the response. It is in the Map shape that we check whether the property inStaff is set to true or false in the first branch based on the group membership claim. In case the property inStaff is false we obfuscate the 'SSN' field in our example...

 

 

The function is a very simple two-step function...

 

 

where the script is as simple as this:

 

val_out = (authorized=='true') ? val_in : '#########'

 

Now, let's see this in action!

 

As an example I have built an Android App that is consuming our 'Patient API'. The API is protected by Okta based on OpenId Connect as described above and the App is registered in Boomi API Management. The App is authorized to use the API with the API Key that is generated as part of the App registration and API authorization in Boomi API Management...

 

 

First of all, if we login as user 'Rene Klomp' who is not a member of Staff, we see that we need to authenticate using username and password with Okta (screenshot 1 below). Furthermore, when logged in we see at the top of the App that we can present any claims embedded in the ID Token in the UI. In this case we present who is logged in into the App by using the name claim. If we request the information for a patient with patient id = 1234 and scroll down to find the SSN we see (as expected - screenshot 2 below) that it is obfuscated as this user is not a member of Staff. When we logout and log back in again as a user who is a member of Staff ('John DiStasio') and scroll down again we can see the SSN is clearly visible - again, as expected (screenshot 3 below)!

 

          

 

Summarizing we have seen how claims inside the Access Token can be used within the API process to perform some conditional processing or logic. As an example we have seen how we can hide or obfuscate a certain field as part of the response based on a certain group membership of the user registered in the external Identity Provider. This is just an arbitrary example and there are of course many possible applications of using these claims within the API process!

Outcomes