DEV Community

Aditya Singh
Aditya Singh

Posted on

[Part 3/3] Securing APIs using JSON Web Token (JWT) in IBM API-Connect v10 using X.509 RSA key pair

Hello Tech Enthusiasts,

Refer previous parts of this series Part 1 and Part 2.

This is final article of our series focusses on the validation of JWT tokens using the APIC v10 jwt-validate policy.

Update API to Validate JWT token

- Select the API ‘JWT Generation and Validation’ and go to Gateway polices tab.

- Drag gatewayscript policy to operation-switch case 1.

- Copy-paste following code

var jwttoken = context.request.header.get('Authorization');

//remove Bearer from the token
context.set('input-jwt', jwttoken.replace(/^Bearer /g, ''));
Enter fullscreen mode Exit fullscreen mode

- Drag jwt-validate and fill the form

  1. JSON WebToken (JWT): input-jwt
  2. Output Claims: decoded.claims
  3. Issuer Claim: apic'for more than one claim, enter regrex pattern (PCRE)'
  4. Audience Claim: id1
  5. Verify Crypto Object: personal_sandbox_tlsp-jwt-keyprofileV1.0.0-ca-0

- Drag ‘set-variable’ and copy the following yaml to source

                - jwt-validate:
                    version: 2.0.0
                    title: jwt-validate
                    jwt: input-jwt
                    output-claims: decoded.claims
                    iss-claim: apic
                    aud-claim: id1
                    jws-crypto: personal_sandbox_tlsp-jwt-keyprofileV1.0.0-ca-0
                    jwe-crypto: ''
Enter fullscreen mode Exit fullscreen mode

- Create Catch policy for error handling

    catch:
      - errors:
          - RuntimeError
        execute:
          - set-variable:
              version: 2.0.0
              title: set-variable
              actions:
                - set: message.status.code
                  value: 400
                  type: number
                - set: message.status.reason
                  value: Bad Request
                  type: string
                - set: message.body
                  value: $(jwt-validate.error-message)
                  type: string
Enter fullscreen mode Exit fullscreen mode

- Save and Publish the API to sandbox catalog

api assembly

API file

swagger: '2.0'
info:
  title: JWT Generation and Validation
  x-ibm-name: jwt-generation-and-validation
  version: 1.0.0
  description: >
    This API has two parts 

    1. Generate JWT: The generate operation takes care of generating jwt token
    and setting that to response payload Authorization header

    2. 
x-ibm-configuration:
  cors:
    enabled: true
  gateway: datapower-api-gateway
  type: rest
  phase: realized
  enforced: true
  testable: true
  assembly:
    execute:
      - operation-switch:
          version: 2.0.0
          title: operation-switch
          case:
            - operations:
                - verb: get
                  path: /generate
              execute:
                - jwt-generate:
                    version: 2.0.0
                    title: jwt-generate
                    jwt: ''
                    iss-claim: request.headers.iss-claim
                    exp-claim: 60
                    description: //This policy is to generate JWT token for client request.
                    jws-alg: RS256
                    jws-crypto: personal_sandbox_tlsp-jwt-keyprofileV1.0.0-key
                    jti-claim: true
                    aud-claim: request.headers.aud-claim
            - operations:
                - verb: get
                  path: /validate
              execute:
                - gatewayscript:
                    version: 2.0.0
                    title: gatewayscript
                    source: >-
                      var jwttoken =
                      context.request.header.get('Authorization');


                      context.set('input-jwt', jwttoken.replace(/^Bearer /g,
                      ''));
                - jwt-validate:
                    version: 2.0.0
                    title: jwt-validate
                    jwt: input-jwt
                    output-claims: decoded.claims
                    iss-claim: apic
                    aud-claim: id1
                    jws-crypto: personal_sandbox_tlsp-jwt-keyprofileV1.0.0-ca-0
                    jwe-crypto: ''
                - set-variable:
                    version: 2.0.0
                    title: set-variable
                    actions:
                      - set: message.body
                        value: $(decoded.claims)
                        type: string
                      - set: message.headers.Content-Type
                        value: application/json
                        type: string
                    description: >-
                      This policy is setting response body from the extracted
                      jwt verification
          otherwise: []
    catch:
      - errors:
          - RuntimeError
        execute:
          - set-variable:
              version: 2.0.0
              title: set-variable
              actions:
                - set: message.status.code
                  value: 400
                  type: number
                - set: message.status.reason
                  value: Bad Request
                  type: string
                - set: message.body
                  value: $(jwt-validate.error-message)
                  type: string
  properties:
    target-url:
      value: http://example.com/operation-name
      description: The URL of the target service
      encoded: false
  activity-log:
    enabled: true
    success-content: activity
    error-content: payload
basePath: /securetoken
paths:
  /generate:
    get:
      responses:
        '200':
          description: success
          schema:
            type: string
  /validate:
    get:
      responses:
        '200':
          description: success
          schema:
            type: string
securityDefinitions:
  clientID:
    type: apiKey
    in: header
    name: X-IBM-Client-Id
security:
  - clientID: []
schemes:
  - https
Enter fullscreen mode Exit fullscreen mode

Testing (Success Scenario)

- Add new GET Request in Postman

- Add X-IBM-Client-Idin header

- In Scripts section, copy paste following code to pre-request to GET /validate request:

var jwtToken = pm.globals.get("jwt_token");

pm.request.headers.add({
    key: "Authorization",
    value: jwtToken

}
)
Enter fullscreen mode Exit fullscreen mode

- First trigger GET /generate request first from Postman to fetch JWT in Authorization

postman screenshot - fetch jwt token

- Now trigger GET /validate request from Postman and verify success 200 Ok with JWT payload details

postman screenshot - successful scenario

Testing (Failure Scenario)

Scenario 1: Token is expired

Response received:
JWT validation failed, because the JWT has expired at Sun Sep 08 2024 21:52:31 GMT+0100 (British Summer Time).

postman screenshot - failure scenario 1

Scenario 2: Token Header is tampered

postman screenshot - failure scenario 2

Scenario 3: Token payload is tampered

postman screenshot - failure scenario 3

Scenario 4: Token signature is tampered

postman screenshot - failure scenario 4

Heroku

This site is built on Heroku

Join the ranks of developers at Salesforce, Airbase, DEV, and more who deploy their mission critical applications on Heroku. Sign up today and launch your first app!

Get Started

Top comments (0)

Heroku

This site is built on Heroku

Join the ranks of developers at Salesforce, Airbase, DEV, and more who deploy their mission critical applications on Heroku. Sign up today and launch your first app!

Get Started

👋 Kindness is contagious

Please leave a ❤️ or a friendly comment on this post if you found it helpful!

Okay