Do you want to establish secure transactions between clients and your APIs? Do you want to know a safe way to represent information between two parties? Or confirm that the data was sent by an authentic source? JSON Web Token (JWT) is a compact way to securely transmit information between two parties. If you have questions regarding API security, read along to discover why MuleSoft JSON Web Token Validation Policy is one of the ways to safely protect your APIs.
What is a JSON Web Token?
JSON Web Token (JWT) is a compact, URL-safe means of representing claims to be transferred between the two parties. The claims in a JWT are encoded as a JSON object that is used as the payload of a JSON Web Signature (JWS) structure or as the plaintext of a JSON Web Encryption (JWE) structure, enabling the claims to be digitally signed or integrity protected with a Message Authentication Code(MAC) and/or encrypted.
In today’s digital world of APIs, it is paramount to protect access to APIs to avoid data being leaked out to the world. The following features of JWT make a compelling case for using JWTs to authenticate and authorize access to APIs.
- JWTs are stateless, making tokens easier to manage.
- JWTs can be used to transfer claims securely between parties.
- JWTs are scalable.
- The payload of a token can be expanded to increase new claims easily.
- JWTs are decoupled in nature allowing authentication to happen on a different server.
- The tokens are compact. JSON format makes the token less verbose than XML. The smaller size allows easier transmission over HTTP.
- JWTs are JSON-based and can be easily parsed by multiple receiving systems, especially mobiles. This enables an industry-wide adoption.
Let’s look at all the details that needs to be filled out while configuring the policy in API Manager.
Specifies from where in the request will JWT be extracted:
- Bearer Authentication Header
- Custom Expression
If you set it to Bearer Authentication Header, JWT will be expected as Bearer.
If you set this field to Custom Expression, a DataWeave Expression returning the token must be provided.
JWT Key origin
The algorithms supported for signature verification are:
- Symmetric algorithms – HMAC using SHA-256, SHA-384, and SHA-512.
- Asymmetric algorithms – RSA using SHA-256, SHA-384, and SHA-512.
- None – no signature validation.
A text field allows the user to provide a certificate against which the token signature will be validated. Currently, only one certificate is supported in the text field.
Any changes to the keys require modification to the policy configuration and re-application of the policies.
- Multiple keys are supported.
- Rotation of cryptographic keys does not require any changes to the policy config.
The policy will automatically calculate the certificate from the key set to validate the signature.
Debugging the JWT Policy
The policy-related debug logs can be enabled through the following package on either the log4j2.xml or directly from Anypoint Runtime Manager.
In many scenarios, we need to validate that the token belongs to a client authenticated by Anypoint Platform. The JWT Validation policy requires the configuration to provide the claim key containing the client id. The policy will then read the value associated with this key and validate the client against lists of client applications defined on Anypoint Platform.
The “Skip Validation” option should be used for non-OIDC compliant token providers.
- This is applicable for JWT providers who are also OIDC compliant.
- Azure ADFS is not supported for true client validation as true dynamic client management between ADFS and Anypoint Platform is non-existent at this point in time.
- In the Azure case, we can use custom claims to define specific validations.
Default claims validations
The “aud” (audience) claim identifies the recipients that the JWT is intended for.
If the audience claim is marked as mandatory, then the policy will fail if the audience claim is not present on the token.
The claim values expects valid values for the API, in a comma-separated format.
By default, the policy checks for the
exp claim, and, if present, validates the token against the expiry time. However, if the claim is not present, the policy will skip the claim validation and allow the API to be called.
To avoid that, it is recommended to mark expiration claim as mandatory.
The “nbf” (not before) claim identifies the time before which the JWT MUST NOT be accepted for processing. The processing of the “nbf” claim requires that the current date/time MUST be after or equal to the not-before date/time listed in the “nbf” claim.
By default, the policy checks for the
nbf claim, and, if present, validates the token against the nbf value. However, if the claim is not present, the policy will skip the claim validation and allow the API to be called. To avoid that, mark nbf claim as mandatory.
Custom claims validations
String-based custom claims
Let’s take the example of the following as available in the JWT token received by the policy.
Now on the policy, we can choose this as a mandatory or non-mandatory claim. For this blog, we will choose the claim as a mandatory claim.
Set up the policy as shown in the document. Any number of singular value-based claims can be added as such.
To check if the string contains a particular value, we use the following
iss: #[vars.claimSet.iss contains("dev-938708")]
Array-based custom claims
We come across situations where claims are in the format of arrays. A few examples are provided below.
The requirement would be to validate these claims before approving the policy to go further. The following example does the validation for groups. The same can be done for any claim in the format of an array.
Value: #[vars.claimSet.groups == ['31cec28d-300f-4180-b3d3-e2bcc30ee890', '4a910140-4fd4-4bf9-aa02-b773d58df24c']]
Where claimSet is the JSON payload of the JWT, the groups can have any value that the business requires the token to be validated against.
Ensure the array-based claim is bounded by #.
The JWT payload is propagated after a successful validation to any subsequent policy or API. The claims can be accessed through the authentication properties from the message.
Accessing iss in the flow. #[authentication.properties.claims.iss]
Access scp in the flow: #[authentication.properties.claims.scp]
To learn more about MuleSoft’s security offerings, check out our on-demand webinar, Protect APIs and secure data with Anypoint Platform.