Skip to end of metadata
Go to start of metadata

You are viewing an old version of this page. View the current version.

Compare with Current View Page History

« Previous Version 8 Next »

Json Web Token - JWT

To access a integration in iHub using a JWT the user must setup a JWT Trigger.

This is done by toggle the JWT option on under webhook triggers.

JSON Web Tokens consist of three parts separated by dots (.), which are:

  • Header

  • Payload

  • eSignature

Therefore, a iHub JWT looks like the following.

xxxxx.yyyyy.zzzzz

The JWT token is then exchanged to a bearer which will be the short lived token that authenticate and triggers the integration flow.

image-20240529-070325.png

RSA 256 Key Pair

First generate a RSA Key pair and download the the key, once downloaded the key can not be recovered if lost. Only option if the key is lost is to generate a new key.

The downloaded file will contain the information needed to exchange the JWT to a Bearer token.

Sign the JWT token

To sign the JWT token use the header and payload.

Header

{
  "alg": "RS256",
  "typ": "JWT"
}

Payload

{
	"iss": "client_id_from_atlassian",
	"sub": "flow_id",
	"aud": "https://ihubprod.rixter.net/incoming/token",
	"iat": "currentTimeSeconds",
	"exp": "plus currentTimeSeconds 1200",
}

Output from the signed will be xxxxx.yyyyy.zzzzz

Exchange the JWT to Bearer

To exchange the JWT to a short lived bearer token,

POST to https://ihubprod.rixter.net/incoming/token

Body:

{
    "grant_type":"urn:ihub:jwt:bearer",
    "assertion":"{{JWT}}"
}

Replace the {{JWT}} with the signed token from above step.

This URN structure indicates:

  • urn: Namespace denoting a Uniform Resource Name

  • ihub: Identifies the IHub system

  • jwt: Specifies a JSON Web Token (JWT)

  • bearer: Indicates the token type is bearer

Response

If valid it will return a body like below

{
  access_token: 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiI0ZjAxOWQ0My00OTAwLTNhOTgtYWEwNi00NjE0M2Y0MGMwNjEiLCJzdWIiOiIzNGNkMzNlNC1iNmFhLTQ4MzctODc1Yi03ZWQ4MWFhMzk2ZDYiLCJleHAiOjE3MTkzMTk0MDMsImlhdCI6MTcxOTMxOTA4MX0.jljJZJMcYD4PapgraNXoZZWUYOR3mPcTgpd_CUeeqCU',
  token_type: 'Bearer',
  expires_in: 1719319403
} 

Use the Bearer token

To trigger the flow send the request to https://ihubprod.rixter.net/incoming/webhook with the http header Authorization: Bearer {{access_token}}

In this call you will include any data that the integration will process.

Example code for trigging flow

Python

pip install PyJWT requests cryptography

The private key is stored in a file called privateKey.txt in this example

 Python
import jwt
import requests
import time
import os
from pathlib import Path
import unittest

class TestIncomingJWTIntegration(unittest.TestCase):

    def setUp(self):
        self.timeout = 10  # seconds
        self.maxDiff = None

    def test_should_return_a_valid_bearer(self):
        headers = {
            "alg": "RS256",
            "typ": "JWT"
        }

        current_time = int(time.time())

        payload = {
            'iss': 'copy from trigger page',
            'sub': 'copy from trigger page',
            'aud': 'https://ihubprod.rixter.net/prod/incoming/token',
            'iat': current_time,
            'exp': current_time + 1200
        }

        private_key_path = Path(__file__).parent / 'privateKey.txt'
        with open(private_key_path, 'r') as file:
            private_key = file.read()

        token = jwt.encode(payload, private_key, algorithm='RS256', headers=headers)
        # print('Generated JWT:', token)

        data = {
            "grant_type": "urn:ihub:jwt:bearer",
            "assertion": token
        }

        access_token = None
        # test generate jwt
        try:
            response = requests.post(payload['aud'], json=data, headers={'Content-Type': 'application/json'})
            response.raise_for_status()
            access_token = response.json().get('access_token')
        except requests.exceptions.RequestException as error:
            print('Error:', error.response.json() if error.response else str(error))

        self.assertIsNotNone(access_token)

        # test trigger flow
        incoming_data = {
            "issueKey": "SERVICENOW-1",
            "description": "HEJ",
            "summary": "Ticket from test case"
        }

        try:
            response = requests.post(
                "https://ihubprod.rixter.net/prod/incoming/webhook/jwt",
                json=incoming_data,
                headers={
                    'Content-Type': 'application/json',
                    'Authorization': f'Bearer {access_token}'
                }
            )
            response.raise_for_status()
            print(response.json())
        except requests.exceptions.RequestException as error:
            print('Error:', error.response.json() if error.response else str(error))

if __name__ == '__main__':
    unittest.main()

Nodejs

The private key is stored in a file called privateKey.txt in this example

 Click here to expand...
var jwt = require('jsonwebtoken');
const axios = require('axios');
import { expect } from "chai";
const fs = require('fs');
const path = require('path');

describe('Incoming JWT integration test', function() {  // Use function() to access this.timeout
  this.timeout(10000);  // Increase timeout to 10 seconds

  it('should return a valid bearer', async () => {

    const headers = {
      "alg": "RS256",
      "typ": "JWT"
    };

    const currentTime = Math.floor(Date.now() / 1000);

    const payload = {
      iss: 'copy from trigger page',
      sub: 'copy from trigger page',
      aud: 'https://ihubprod.rixter.net/prod/incoming/token',
      iat: currentTime,
      exp: (currentTime + 1200)
    };

    const privateKeyPath = path.join(__dirname, 'privateKey.txt');
    const privateKey = fs.readFileSync(privateKeyPath, 'utf8');

    const token = jwt.sign(payload, privateKey, { algorithm: 'RS256', header: headers });
    //console.log('Generated JWT:', token);

    const data = {
      "grant_type": "urn:ihub:jwt:bearer",
      "assertion": token
    };

    let access_token;
    //test generate jwt
    try {
      const response = await axios.post(payload.aud, data, {
        headers: {
          'Content-Type': 'application/json'
        }
      });
      access_token = response.data.access_token;
    } catch (error) {
      console.error('Error:', error.response ? error.response.data : error.message);
    }
    expect(access_token).not.to.be.equal(undefined);
    //test trigger flow
    const incomingData = {
      "issueKey": "SERVICENOW-1",
      "description": "HEJ",
      "summary":"Ticket from test case"
    };
    try {
      const response = await axios.post("https://ihubprod.rixter.net/prod/incoming/webhook/jwt", incomingData, {
        headers: {
          'Content-Type': 'application/json',
          'Authorization': 'Bearer '+access_token
        }
      });
      console.log(response.data)
    } catch (error) {
      console.error('Error:', error.response ? error.response.data : error.message);
    }

  });
});
  • No labels