Hi, I'm Krithika Prakash from IBM. I'm the SaaS security architect for API Connect & Gateways in the Cloud division.
API Connect is constantly enhancing the way you can secure APIs with support for several out of the box policies in the assembly. One of the ways of securing APIs is using JSON Web Tokens (JWT). In this video, I'll provide a sample API (see Reference section below) and explain how it generates a JWT token and subsequently validates it. Also a transcript of the video is documented in this blog below.
The best part of this tutorial is that, you can try out this scenario using the Bluemix API Connect Essentials edition for free. You don't have to install anything or you don't need to have access to any specific systems. If you don't have a Bluemix account yet, sign up for one now, provision an API Connect instance and launch the API Connect Manager UI.
Once you are there, first import the attached swagger file. You can find the sample API swagger file that I have put together in the reference link. Create a product and publish this API to a product. I'm not going over a lot of details on this , but it is only a few clicks. Here I have already imported the API and published it to a product. Once you have done that, you should be able to test it right from the test tool within the API Manager. Let me show you how to test the API for JWT generation and subsequent JWT validation.
As you can see, this API has two operations - generate-jwt and validate-jwt. Choose operation "generate-jwt". The generate-jwt operation has two parameters for specifying the issuer claim and the audience claim to be included in the JWT. I used 'apic' for issuer and 'id1' for audience . Click Invoke. There you go. You will see the generated JWT in the output.
Next, let's test the validation. Copy and paste the generated JWT token into the validate-jwt operation "Authorization header". Make sure to prefix the token with the string "Bearer" as shown . Click "invoke" and you will see that the JWT token is validated and decoded claims are being displayed.
You should be all set now. You can import the API, test it out, use it as a reference and make modifications as needed for your environment. However if you are interested in knowing more about the exact configuration of this API, keep watching.
Let's look at the assemble section of the API.Set JWK keys
First I do a set-variable to set the JWK keys into a runtime variable. I created a JWK key using HS256 algorithm for testing purposes using an online JWK generator website (https://mkjwk.org/). There are also other ways of creating JWK keys securely, say using nodejs libraries. Note that, this key will be used for both generation and validation of the JWT tokens.Switch based on the request
Next, in the switch policy, I have created three cases:
1) If the request is for jwt-generate, do a JWT generation
2) If the request is for jwt-validate and it has the JWT token in the Bearer Authorization header, then do a JWT validation.
3) If neither of these, then redirect the client to my idp.Generate JWT
In the jwt-generate policy, I specify that the generated JWT should be stored in this run time variable named generated-jwt. I use the request headers iss-claim and aud-claim to be included in the JWT. For the key, I refer to the JWK runtime variable 'hs256-key' that I created in the previous set-variable policy. Since I created a hs256 JWK key, I choose the HS256 algorithm correspondingly. Note that besides JWK key, there are also other types of keys that you can use here - namely a shared secret key, or an RSA private key. However these two key types need crypto objects to be created in the DataPower gateway. So, if you don't have access to the DataPower gateway used by API Connect, as we now have here in the Bluemix environment, then JWK key is the only key type that you can use at this point. In this sample, I have only signed the JWT token. The rest of the parameters related to encryption are ignored. You can obviously extend this API to encrypt the token also. Simply specify the key for encryption. See sample in the Reference section below.Output JWT to the client
After the jwt-generate policy, I added a gatewayscript policy that will just write out the generated token into the message body. This is done for my convenience, so that I can copy and paste the token for subsequent validation. It could be different in your environment based on the needs.
This completes the JWT generation configuration. Next let's look at how validation is being done.Extract JWT token from Authorization Bearer header
First, I extract the JWT token from the Authorizatoin Bearer header in a gatewayscript policy. Again, as of 126.96.36.199, this manual extraction of the JWT is required. The extracted JWT is placed in a run time variable called input-jwt.Validate JWT
In the validate-jwt policy, I specify the runtime variable input-jwt where the JWT is extracted to. I specify that the decoded claims should go into a run time variable named decoded-claims. It is more likely that you will need these decoded claims for your subsequent processing. I also validate the issuer and the audience claims. But, these are optional. If the input JWT does not have these values for issuer and audience claims, then it will be rejected.
For the key, I specify the same JWK key hs256-key.Output decoded claims
The validate-jwt token is followed by another gatewayscript policy which will write out the validated claims in the message body.Redirect to IDP
As the last case in this switch block, I handle the scenario when the request does not contain a JWT token. In this API, I show a sample scenario where the client could be redirected to an IDP to obtain a JWT token or it could be redirected to an API that generates the JWT within API Connect. You could handle this in any appropriate way to suit your environment.Error handling
Finally, I handle the error in the catch policy. I catch the errors from the JWT policies and write it out to the client here.
That's it. This concludes the explanation of the API assembly. You see how with only a few clicks, we could create a powerful API that can be used for securing your resources. . You can get creative. For example, you can enhance this API to generate an embedded JWT token by using the 'private claims' property of the jwt-generate policy. The possibilities on extending this API for your needs are endless.
So, please leave a comment if you found this video useful or if you would like to see more such sample APIs for various other out of the box policies supported in API Connect.
Thanks for watching !Reference:
1) You can download the sample API jwt-api.yaml
used in this tutorial.
2) A sample API that does both signing and encryption of JWT tokens using JWK can be downloaded here -> jwtapi_sign_enc.yaml
Note that for encryption, you need to create the key length according to the algorithm.Trouble Shooting:
When trouble shooting JWT generate policy, make sure to update the Gatewayscript in "Catch" policy to return the error from the JWT generate policy as shown below:
[contact-form][contact-field label='Name' type='name' required='1'/][contact-field label='Email' type='email' required='1'/][contact-field label='Website' type='url'/][contact-field label='Comment' type='textarea' required='1'/][/contact-form]