API Connect

 View Only

Securing APIs using JSON Web Tokens (JWT) in API Connect - Video Tutorial

By Krithika Prakash posted Tue August 16, 2016 08:19 PM

  
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.

 

[embed]https://www.youtube.com/watch?v=ZgFAU2oQ0ws[/embed]

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 5.0.3.0, 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:

apim.setvariable('message.body',apim.getvariable('jwt-generate.error-message'));

[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]









7 comments
55 views

Permalink

Comments

Fri February 01, 2019 10:24 PM

Looks like your bearer token is an access token, not a JWT token. The ability to introspect it confirms this. Hence the validation failure.

Mon January 21, 2019 03:03 AM

Hi Kritika,

Just checking with you if we can authenticate the user with our LDAP group? if yes can help me to provide me some guidance

Thu November 08, 2018 12:13 PM

If you are using crypto objects in datapower don't these get blown away when APIC reloads a gateway? When that happens do you need to reload the crypto objects?

Wed July 18, 2018 10:49 AM

Hi,
Apart from authentication, can we do authorizations also with JWT ?

Fri April 27, 2018 10:52 AM

Thank You krithika , i got your point . But how can i use this in particular service as i am very much new in this technology please give me suggestion.

Mon October 09, 2017 02:46 PM

It took me a while to realize that the demonstration was not showing possible inputs, but mandatory inputs (apic and id1 values). The generate works for any inputs, but the validate only works when the JWT token was created with the inputs that are hardcoded in the API definition:
iss-claim: apic
aud-claim: id1
Unless those values were used on the generate request the validate will fail. (it can only validate the token created from that one set of inputs).

Mon March 06, 2017 06:05 PM

Hi Krithika - I am working on a scenario in which I would like to use the jwt-validate policy to validate and extract the set of claims encapsulated in a JWT that has been returned by an APIC OAuth2.0 API. The call to the OAuth2.0 endpoint returns me an access token, which I believe is a JWT :

{ "token_type":"bearer", "access_token":"AAEkYThiMzg0MDUtZTAyZS00YzU5LWEwNzItNDA1YzgzMjI2ZDIyTafikdtTxdI3bvnMP8uj9izi_ag5xer6KNTcBHIeaApbGC-9jW0sLGZ8O1wrRLSNuA0FCN1twYf7URxn480arkQUr10wvlGjhKrh_xQF3ao", "expires_in":3600, "scope":"betterbank" }

My jwt-validate policy fails at execution time with :

{ "httpCode":"500", "httpMessage":"Invalid-JWT-Validate", "moreInformation":"JWT validation failed" }

I am able to successfully parse the access token by calling the introspect endpoint, and get the following response :

{ "active":true, "token_type":"bearer", "client_id":"a8b38405-e02e-4c59-a072-405c83226d22", "username":"weathermobileapp", "sub":"weathermobileapp", "exp":1488826023, "expstr":"2017-03-06T18:47:03Z", "iat":1488822423, "nbf":1488822423, "nbfstr":"2017-03-06T17:47:03Z", "scope":"betterbank", "client_name":"AcmeApp01" }

all of which seems reasonable. My jwt-validate policy configuration does not specify any value for claims checking or any JWK/crypto objects. Has the signature of the APIC OAuth2.0 access token been encrypted ? (I can't find any discussion in the docs) and if so, where do I get the values of the JWK or cert that I need to be able to configure my policy ?