How to automate JWT creation in Postman

Hey all! I recently configured Postman so that it will automatically pull a new JSON Web Token (JWT) every time you send an API call.

To do this, you set up a variable to store the token, and then add a Pre-Request Script to generate the token using your ClientID and SecretID.

At the top collection level, define a Pre-Request Script as follows:

const tokenUrl = 'https://xxxxxx.api.cloud.sailpoint.com/oauth/token';
const clientId = 'xxxxxxx';
const clientSecret = 'xxxxxx';

const getTokenRequest = {
  method: 'POST',
  url: tokenUrl,
  body: {
      mode: 'formdata',
      formdata: [
          { key: 'grant_type', value: 'client_credentials' },
          { key: 'client_id', value: clientId },
          { key: 'client_secret', value: clientSecret }
      ]
  }
};

pm.sendRequest(getTokenRequest, (err, response) => {
  const jsonResponse = response.json();
  const newAccessToken = jsonResponse.access_token;

  pm.variables.set('access_token', newAccessToken);
});

Update your org, ClientID, and Secret for your Personal Access Token from IDN, and save it.

(Note: You may see an error/warning when you first save this, because the variable has not yet been set, but once you make one API call, it will be fine).

Finally, update the Authorization tab, and select Bearer Token for Type , and use the variable {{access_token}} in the Token field. For individual API items, set them to “Inherit from parent”

6 Likes

Thanks for this Rich.
I created the Pre-request script, made a few changes to use my environment variables for the tokenUrl, clientID and clientSecret:

const tokenUrl = pm.environment.get("oauthToken");
const clientId = pm.environment.get("ClientID");
const clientSecret = pm.environment.get("ClientSecret");

and created the access-token variable. But I still get the JWT validation failed message. I see that the token call is being processed in the console, and an access_token is being returned.

Any idea what I’m missing?

Thanks,
Chris

Whoops! I left out a piece:

Update the Authorization tab, and select Bearer Token for Type , and use the variable {{access_token}} in the Token field. For individual API items, set them to “Inherit from parent”

(I updated the main post with this info as well).

Rich

1 Like

Thanks Rich, that worked great.

1 Like

Awesome stuff @Rich_Miller!

Note: External customers will likely need to reference *.api.identitynow.com instead of *.api.cloud.sailpoint.com.

Also if anyone wants to extract these to Postman Environment variables (like I use) it makes switching tenants much easier. You can do something like this:

const url = pm.environment.get( 'api-url' ) + '/oauth/token';
const clientId = pm.environment.get("pat-id");
const clientSecret = pm.environment.get("pat-secret");

Where:

  • api-url is the IdentityNow API gateway for your tenant - e.g. https://acme.api.identitynow.com
  • pat-id is the Personal Access Token ID given from your tenant
  • pat-secret is the Personal Access Token secret given from your tenant
4 Likes

@colin_mckibben can we add this feature to the official SailPoint Postman collection?

Since a Bearer Token has a life of 12 hours. I made additions to script to get tokens only when they expire.

const tokenUrl = pm.environment.get( 'api-url' ) + '/oauth/token';
const clientId = pm.environment.get("pat-id");
const clientSecret = pm.environment.get("pat-secret");

const getTokenRequest = {
  method: 'POST',
  url: tokenUrl,
  body: {
      mode: 'formdata',
      formdata: [
          { key: 'grant_type', value: 'client_credentials' },
          { key: 'client_id', value: clientId },
          { key: 'client_secret', value: clientSecret }
      ]
  }
};


var moment = require('moment');
if(!pm.environment.has('time')){
    pm.environment.set('time',moment());
}

if(moment(pm.environment.get('time')) < moment())
{
    var time = moment();
    time.add(12,'hours');
    pm.environment.set('time',time);
    pm.sendRequest(getTokenRequest, (err, response) => {
    const jsonResponse = response.json();
    const newAccessToken = jsonResponse.access_token;
    pm.environment.set('access_token', newAccessToken);
});

}
3 Likes

Some time ago I created something similar.
I was storing the token request in environment variables as I didn’t know you could form the request in the script itself, so I adapted it to your request formation.
My script uses the expires_in from the token, adds some logs to console and does some request validation.
Definitely not perfect, but perhaps some might be useful for you to adapt your setup.

var moment = require("moment");

const tokenUrl = pm.environment.get( "api-url" ) + "/oauth/token";
const clientId = pm.environment.get("pat-id");
const clientSecret = pm.environment.get("pat-secret");

const getTokenRequest = {
  method: "POST",
  url: tokenUrl,
  body: {
      mode: "formdata",
      formdata: [
          { key: "grant_type", value: "client_credentials" },
          { key: "client_id", value: clientId },
          { key: "client_secret", value: clientSecret }
      ]
  }
};

if (!pm.environment.has("access_token")){
    console.log("creating access_token variable in environment")
    pm.environment.set("access_token","")
    }
if (!pm.environment.has("access_token_valid_until")){
    console.log("creating access_token_valid_until variable in environment")
    pm.environment.set("access_token_valid_until","")
    }

var access_token = pm.environment.get("access_token")
var access_token_valid_until = pm.environment.get("access_token_valid_until")

console.log("access_token empty? " + (access_token == ""));
console.log("access_token_valid_until empty? " + (access_token_valid_until == ""));
console.log("access_token still valid? "+ (access_token_valid_until != "" && !(new Date(access_token_valid_until) < moment())))

if (access_token == "" || access_token_valid_until == "" || new Date(access_token_valid_until) < moment()){
    pm.sendRequest(getTokenRequest, (error, response) => {
    if (error) {
        console.log(error);
    }
    pm.test("Response with token should be OK", () => {
        pm.expect(error).to.equal(null);
        pm.expect(response).to.have.property("code", 200);
        pm.expect(response).to.have.property("status", "OK");
        pm.environment.set("access_token", response.json().access_token);
        pm.environment.set("access_token_valid_until", moment().add(response.json().expires_in, "seconds"));
    });
    });
}

Hey @tysremi, thanks for the addition! We also have one built into our official collections for V3 and Beta APIs: Official: IdentityNow Postman Workspace

I made a few adjustments to @tysremi script by adding a ‘tenant’ element. This allows us to easily change the ID when working with multiple customer Tenants. Also, since the ‘pm.sendRequest’ function is asynchronous it does not block the execution of the code that follows it. As this could be problematic I wrapped the rest of the code in a callback function that is called when the request is completed. Now the rest of the code only runs once the response from the request has been received.

You will need to add ‘tenant’ as a value to the Environment.

var moment = require("moment");

const tenant = pm.environment.get("tenant");
const apiUrl = pm.environment.get("api-url");
const tokenUrl = apiUrl.replace("{{tenant}}", tenant) + "/oauth/token" ;
const clientId = pm.environment.get("pat-id");
const clientSecret = pm.environment.get("pat-secret");

const getTokenRequest = {
  method: "POST",
  url: tokenUrl,
  body: {
      mode: "formdata",
      formdata: [
          { key: "grant_type", value: "client_credentials" },
          { key: "client_id", value: clientId },
          { key: "client_secret", value: clientSecret }
      ]
  }
};

if (!pm.environment.has("access_token")){
    console.log("creating access_token variable in environment")
    pm.environment.set("access_token","")
    }
if (!pm.environment.has("access_token_valid_until")){
    console.log("creating access_token_valid_until variable in environment")
    pm.environment.set("access_token_valid_until","")
    }

var access_token = pm.environment.get("access_token")
var access_token_valid_until = pm.environment.get("access_token_valid_until")

console.log("access_token empty? " + (access_token == ""));
console.log("access_token_valid_until empty? " + (access_token_valid_until == ""));
console.log("access_token still valid? "+ (access_token_valid_until != "" && !(new Date(access_token_valid_until) < moment())))

if (access_token == "" || access_token_valid_until == "" || new Date(access_token_valid_until) < moment()){
    pm.sendRequest(getTokenRequest, (error, response) => {
        if (error) {
            console.log(error);
        }
        pm.test("Response with token should be OK", () => {
            pm.expect(error).to.equal(null);
            pm.expect(response).to.have.property("code", 200);
            pm.expect(response).to.have.property("status", "OK");
            pm.environment.set("access_token", response.json().access_token);
            pm.environment.set("access_token_valid_until", moment().add(response.json().expires_in, "seconds"));
        });
    });
}