Internal stuff of Mulesoft + JWT

ANUPAM GOGOI
7 min readFeb 19, 2023

--

Introduction

In this brief article, I would like to explore some internal stuff of the Mulesoft JWT Validation policy. The target audience of the article is the advanced ones who have in-depth knowledge of the platform i.e how the Mulesoft platform works internally.

Article Division

As it will be an in-depth article, I would like to start everything from scratch. You may skip some parts if you have good knowledge. I will divide the article into the below sections.

JWT Configuration in Keycloak

Validate JWT with Java

Configure JWT in Mulesoft

Check the Source code of the Mulesoft JWT policy

JWT Configuration in Keycloak

There are tons of articles regarding JWT on the internet, so I will not delve into it. For this demo, I am going to use the Keycloak Identity Server for the JWT generation (I found it free of use and quite simple).

Keycloak installation

If you have Docker in your machine then it's the best way to try it out.

docker run -p 8080:8080 -e KEYCLOAK_ADMIN=admin -e KEYCLOAK_ADMIN_PASSWORD=admin quay.io/keycloak/keycloak:20.0.3 start-dev

That's all. You will have an excellent Keycloak server up & running.

Browse to http://localhost:8080 and you will be presented with a friendly welcome screen as seen below.

Configure a Client

First, we need to configure a client. Click the Clients menu option on the left-hand side and then click Create client

Add the client name as shown in the below screenshot:

General Settings

Add the capabilities to the client:

Capabilities

And Save.

In the Credentials section of the client (mule), you can find the Client secret as shown below:

client_secret

Find the Well-Known URL of Keyclock

Now let's find out the well-known URL of Keyclock. Click

Configure → Realm settings → General

You can see that there is a link OpenID Endpoint Configuration. That's the well-known endpoints exposed by the Keycloak server. Cool.

In my case, it's

http://localhost:8080/realms/master/.well-known/openid-configuration

Invoke the endpoint in Postman or anywhere of your choice and you are in the game:

Well Known

Generate JWT

Now, let's generate a JWT by invoking the token endpoint.

Below is my CURL command to generate JWT:

curl — location ‘http://localhost:8080/realms/master/protocol/openid-connect/token' \
— header ‘Content-Type: application/x-www-form-urlencoded’ \
— data-urlencode ‘client_id=mule’ \
— data-urlencode ‘grant_type=client_credentials’ \
— data-urlencode ‘client_secret=SIGlvYOaD8cJ3DggiW2UBw9E3zpkpWrS’ \
— data-urlencode ‘scope=openid’

Check my Postman screen-shot:

Postman JWT

The id_token is our most wanted JWT. You can decode it to check its contents:

JWT.io

In the next section let's validate the token using Java code.

Validate JWT with Java

I am going to write the simplest ever possible code to validate a JWT token against the JWKS URL.

Note that from the well-known URL, we can easily find the JWKS URL. In my case it is:

http://localhost:8080/realms/master/protocol/openid-connect/certs

What it does is no genius. In short, it exposes a set of keys (kid) against whom we can validate our JWT. Well, I am not going to enter in details of that because the internet is already full of such information.

For the Java code, I am going to use the Nimbus JOSE+JWT libraries. Below is the code snippet:

package com.utility;

import com.nimbusds.jose.JWSAlgorithm;
import com.nimbusds.jose.jwk.source.JWKSource;
import com.nimbusds.jose.jwk.source.RemoteJWKSet;
import com.nimbusds.jose.proc.JWSKeySelector;
import com.nimbusds.jose.proc.JWSVerificationKeySelector;
import com.nimbusds.jose.proc.SecurityContext;
import com.nimbusds.jwt.JWTClaimsSet;
import com.nimbusds.jwt.proc.ConfigurableJWTProcessor;
import com.nimbusds.jwt.proc.DefaultJWTProcessor;

import java.net.URL;

public class App {
public static void main(String[] args) {
validate("eyJhbGciOiJSUzI1NiIsInR5cCIgOiAiSldUIiwia2lkIiA6ICJIYkVIUE5COWRLOWlpNG16YUhzejJTYUZzTFo5ZkloYTdwcmpPdW5YUE5NIn0.eyJleHAiOjE2NzY4MTQ4NTYsImlhdCI6MTY3NjgxNDc5NiwiYXV0aF90aW1lIjowLCJqdGkiOiIyOGYxODUzYy00MGRiLTQ2ZGItYjc2My00ZTlhMTkyZDYzODAiLCJpc3MiOiJodHRwOi8vbG9jYWxob3N0OjgwODAvcmVhbG1zL21hc3RlciIsImF1ZCI6Im11bGUiLCJzdWIiOiIyYmRiMjUzMy04Y2ZlLTQ3ZWEtOWY0Zi1lOGJlMDEyYzdhM2EiLCJ0eXAiOiJJRCIsImF6cCI6Im11bGUiLCJhdF9oYXNoIjoiM3FGU0otNXI0R2NOT0ZoeWxpZnlIZyIsImFjciI6IjEiLCJjbGllbnRIb3N0IjoiMTcyLjE3LjAuMSIsImNsaWVudElkIjoibXVsZSIsImVtYWlsX3ZlcmlmaWVkIjpmYWxzZSwicHJlZmVycmVkX3VzZXJuYW1lIjoic2VydmljZS1hY2NvdW50LW11bGUiLCJjbGllbnRBZGRyZXNzIjoiMTcyLjE3LjAuMSJ9.E4nINN9ebHnYxfJovL_Qwd9uB6AyGE6-jwSWiENfxzAOy0iZJriT0bsENjgf3XuoA0amfEwN6DKBr8eQeVxdkpOhq_rZpo4GgDYz11cOvYX-3-qVbr2-LCssSxmqcvvNq1lWj6VqkbcVGHZzrvjHdST05lNAJG1Jfnd59u9Tjoxmy7RJktVfasaSPLZm_qdmffAAPXKwLA-XD9HOZsUV-MHgOq2yg7q-sdzIokWtfCnKdjGjZ3XVMmTNAa_H1Vqh8Nab3Nsi1kxuAHi10Xac70NUgATcSEICfclwMmS02SkRo5PZbDRinKQMWWNmoWRCaS97qpT_NKb6Urez0ea1uw");
}


public static void validate(String accessToken) {
try {
ConfigurableJWTProcessor<SecurityContext> jwtProcessor = new DefaultJWTProcessor<>();

JWKSource<SecurityContext> keySource = new RemoteJWKSet<>(new URL("http://localhost:8080/realms/master/protocol/openid-connect/certs"));
JWSKeySelector<SecurityContext> keySelector = new JWSVerificationKeySelector<>(JWSAlgorithm.RS256, keySource);
jwtProcessor.setJWSKeySelector(keySelector);

JWTClaimsSet claimsSet = jwtProcessor.process(accessToken, null);
System.out.println(claimsSet.toJSONObject());
}
catch (Exception e){
e.printStackTrace();
}

}

}

When the token is valid you get the below output:

{at_hash=3qFSJ-5r4GcNOFhylifyHg, sub=2bdb2533-8cfe-47ea-9f4f-e8be012c7a3a, clientHost=172.17.0.1, clientId=mule, email_verified=false, iss=http://localhost:8080/realms/master, typ=ID, preferred_username=service-account-mule, clientAddress=172.17.0.1, aud=mule, acr=1, azp=mule, auth_time=0, exp=1676814856, iat=1676814796, jti=28f1853c-40db-46db-b763-4e9a192d6380}

When the JWT expires you get the below error:

How cool!!!!!

And just to let you know that this is the magic that Mulesoft uses in the JWT Policy in a sophisticated way. No more secrets!

Configure JWT in Mulesoft

Create a RAML in the Design Center → Publish to Exchange → Import it in API Manager → Create the API.

After creating the API, just apply the JWT Validation policy to it.

JWT Validation policy

That's it.

Check the Source code of the Mulesoft JWT policy

This part is cool where we will actually debug the JWT Policy of Mulesoft. In my previous articles, I wrote about how to debug the whole Mulesoft Runtime (I am not talking about debugging a Mulesoft application, it's for dummies :))

This is what we are going to do. The first step is how to get hold of the JWT Validation policy code. Check the below steps:

Configure Anypoint Platform credentials

The best way is to download a standalone Mulesoft Runtime 4. x on your machine. Then edit the wrapper.conf with the platform client_id & client_secret. In my case, I just retrieved the environment's credentials to which I am going to deploy my API.

Also, set the configuration for the debugging:

I will not enter that much detail as you can already check those stuff in the article I cited.

API Development

I believe when you created the API in API Manager you got the API Instance ID. So, with that just create a mock implementation on your local machine.

Now, export the zip and publish it to your standalone Mule Runtime (not Anypoint IDE) i.e put it in the /apps folder.

Run the standalone Mule Runtime and wait for some moments. Note that you will need to attach a debugger to the runtime. I normally use Intellij

Although at this moment we are not going to debug anything, I just kept everything configured for later use.

After some time you can see that the JWT policy is downloaded automatically and installed in your standalone Mulesoft Runtime in the following location.

That's awesome.

Explore the JWT policy

Now, we have all we wanted in hand. We can explore the jwt-validation-1.3.1-mule-policy.jar. Just unzip it with any tool you prefer.

Check the exploded jar. Inside it, there are many other jars. However, I am interested only in that marked one.

This is the jar file that I will import into my IntelliJ IDE for debugging and that will be the cool thing.

Now let's make a request to my API that I deployed to my standalone Mulesoft Runtime. See what's happening:

Debug

This is the method executed for JWT Validation. And if you deep dive into the code you will find that Mulesoft uses the Nimbus JOSE + JWT libs with a sophisticated way to validate the JWT. No secrets.

Conclusion

Well, that's all for today. Hope you find the article insightful. 100% of the articles on the internet don't dive into what's under the hood. That's why I decided to expose the truth underneath the platform.

So, what do you think? JWT is complex? Hell no!

See you soon.

--

--