oauthtokenjackhenry-jxchange

JX OAuth Request Token Issue, getting invalid_client despite having the values obtained from JH


We are trying to test the Scenario: JX OAuth Request Token request.

But when sending the "Request Token" request, we are getting:

{
"error": "invalid_client",
"error_description": "client authentication failed"
}

We have set

in the Variables tab of the Scenario: JX OAuth

We have set the X-InstitutionRoutingID, X-Environment, X-ValidConsumerName, X-ValidConsumerProduct, X-ConsumerName and X-ConsumerProd in the DMZ Silverlake OAuth Environment, and is the one set to Active.

But when sending the "Request Token" request, we are getting:

{
"error": "invalid_client",
"error_description": "client authentication failed"
}

I'm trying it on Postman with this Environment:

{
    "id": "84771fdb-ccf5-4650-94ae-c76c03e16d7f",
    "name": "DMZ Silverlake OAuth",
    "values": [
       {
          "key": "X-AuditUser",
          "value": "",
          "type": "default",
          "enabled": true
       },
       {
          "key": "X-AuditWorkStation",
          "value": "",
          "type": "default",
          "enabled": true
       },
       {
          "key": "X-InstitutionRoutingID",
          "value": "011001276",
          "type": "default",
          "enabled": true
       },
       {
          "key": "X-Environment",
          "value": "TEST",
          "type": "default",
          "enabled": true
       },
       {
          "key": "X-ValidConsumerName",
          "value": "",
          "type": "default",
          "enabled": true
       },
       {
          "key": "X-ValidConsumerProduct",
          "value": "",
          "type": "default",
          "enabled": true
       },
       {
          "key": "X-NumberOfRecords",
          "value": "20",
          "type": "default",
          "enabled": true
       },
       {
          "key": "X-CursorStartingPoint",
          "value": "0",
          "type": "default",
          "enabled": true
       },
       {
          "key": "X-ConsumerName",
          "value": "",
          "type": "default",
          "enabled": true
       },
       {
          "key": "X-ConsumerProd",
          "value": "",
          "type": "default",
          "enabled": true
       },
       {
          "key": "X-SubscrpId",
          "value": "",
          "type": "default",
          "enabled": true
       },
       {
          "key": "X-EventProd",
          "value": "",
          "type": "default",
          "enabled": true
       },
       {
          "key": "X-FIUserProfile",
          "value": "DemoAcct",
          "type": "default",
          "enabled": true
       },
       {
          "key": "auth_client_assertion",
          "value": "",
          "type": "default",
          "enabled": true
       }
    ],
    "_postman_variable_scope": "environment",
    "_postman_exported_at": "2025-10-10T13:58:59.916Z",
    "_postman_exported_using": "Postman/11.66.4"
}

The I have a collection with these Variables:

And on that collection there is a request:

With an x-www-form-urlencoded content type body with this variables:

grant_type = client_credentials
client_id = {{auth_client_id}}
client_assertion_type = urn:ietf:params:oauth:client-assertion-type:jwt-bearer
client_assertion = {{auth_client_assertion}}
scope = {{auth_scope}}

It has a pre script:

const uuid = require('uuid');
const navigator = {}; // Fake a navigator object for the jsrsasign lib.
const window = {}; // Fake a window object for the jsrsasign lib.
eval(pm.collectionVariables.get("jsrsasign-js")); // Load the jsrsasign library.

let expirationTimeMs = (new Date()).getTime() + (300 * 1000);
// Create Header and Payload objects
let header = {
  "alg": "RS256",
  "typ": "JWT"
};
let payload = {
  "jti": uuid.v4(),
  "iss": pm.variables.get("auth_client_id"),
  "aud": pm.variables.get("auth_access_token_url"),
  "sub": pm.variables.get("auth_client_id"),
  "exp" : expirationTimeMs
};

console.info("payload:");
console.info(payload);

// Use the jsrsasign module to create the signed JWT (client assertion).
const privateKeyVariableName = 'auth_private_key';
let privateKey = pm.variables.get(privateKeyVariableName);
console.info("privateKey:");
console.info(privateKey);
if (!privateKey || privateKey.toLowerCase().indexOf('vault') >= 0) {
  console.error(`No private key found in variable '${privateKeyVariableName}': ${privateKey}`);
  console.error('Stopping execution.');
  pm.execution.skipRequest();
}
console.info('Parsing private key...');
let privateKeyObj = KEYUTIL.getKey(privateKey);
if (!privateKeyObj.isPrivate) {
  console.error('this is not a private key');
}

console.info('Signing client assertion...');
let signedJwt = KJUR.jws.JWS.sign(header.alg, JSON.stringify(header), JSON.stringify(payload), privateKeyObj);
pm.environment.set("auth_client_assertion", signedJwt);
console.log('"private_key_jwt": ' + signedJwt)

And a post script:

pm.test("Status code should be 200", function () {
  pm.response.to.have.status(200);
  const jsonResponse = pm.response.json();
  pm.collectionVariables.set("consumer_access_token", jsonResponse.access_token);
});

Is a POST with the URL set to: {{auth_access_token_url}}

All of that can be read and obtained from the JH docs:

https://jackhenry.dev/jxchange-soap/tutorials/api-test-tools/postman_oauth/#configure-jx-oauth-scenario

and

https://www.postman.com/speeding-comet-421858/jack-henry-public/environment/15883335-9e9bacef-ad29-4695-964d-ebbf41cd7770

Thanks


Solution

  • the issue was on the key/pair generated with ES256, and the pre-script in the postman collection set the 'alg' header as RSA256, I just changed it to ES256 and it worked.

    So thus question can be marked as resolved, but I don't know how to do it.

    Regards!