Post

[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

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

2). Drag gatewayscript policy to operation-switch case 1

3). Copy-paste following code

1
2
3
4
var jwttoken = context.request.header.get('Authorization');

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

4). Drag jwt-validate and fill the form

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

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

1
2
3
4
5
6
7
8
9
                - 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: ''

6). Create Catch policy for error handling

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
    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

7). Save and Publish the API to sandbox catalog

api assembly api assembly

Testing (Success Scenario)

1). Add new GET Request in Postman

2). Add X-IBM-Client-Idin header

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

1
2
3
4
5
6
7
8
var jwtToken = pm.globals.get("jwt_token");

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

}
)

4). First trigger GET /generate request first from Postman to fetch JWT in Authorization

postman screenshot - fetch jwt token postman screenshot - fetch jwt token

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

postman screenshot - successful scenario 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 postman screenshot - failure scenario 1

Scenario 2: Token Header is tampered

postman screenshot - failure scenario 2 postman screenshot - failure scenario 2

Scenario 3: Token payload is tampered

postman screenshot - failure scenario 3 postman screenshot - failure scenario 3

Scenario 4: Token signature is tampered

postman screenshot - failure scenario 4 postman screenshot - failure scenario 4

API File

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
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

— Keep Learning 😊

— Aditya Singh

If this article helped you in someway and want to support me, you can …

This post is licensed under CC BY 4.0 by the author.

Comments powered by Disqus.

Buy Me A Coffee