How to persist an OAuth2 token (or use a refresh token) in Postman collections?

39,267

Solution 1

I found an answer here on github.

First, setup these environment variables:

  • url : (your API endpoint)
  • access_token : (blank)
  • refresh_token : (blank)
  • client_id : (your client_id)
  • client_secret : (your client_secret)
  • username : (your username)
  • password : (your password)

Next, create a new call which gets an access_token using the password grant_type.

In my case, I POST to {{url}}/access_token. Sent with this call is the following information as form-data key/value pairs specified in the Body tab:

  • grant_type : password
  • username : {{username}}
  • password : {{password}}
  • client_id : {{client_id}}
  • client_secret : {{client_secret}}

Sending this POST will result in something like this response:

{
  "access_token": "kciOMpcmRcGTKfoo",
  "token_type": "Bearer",
  "expires_in": 3600,
  "refresh_token": "DMGAe2TGaFbar"
}

Then, in the Tests tab, I added the following code to assign two of the environment variables, access_token and refresh_token.

var data = JSON.parse(responseBody);
postman.setEnvironmentVariable("access_token", data.access_token);
postman.setEnvironmentVariable("refresh_token", data.refresh_token);

NOTE: I also put a test in there, just to make sure at least this call worked properly as well, although this has nothing to do with the original question:

var jsonData = JSON.parse(responseBody);
tests["token_type is Bearer"] = jsonData.token_type === "Bearer";

Now any new call I create can use the access_token generated by that first call as an environment variable like this: {{access_token}}. In my case, I go to the Headers tab in a call/test and add this key/pair:

  • Authorization : Bearer {{access_token}}

Bonus points: I haven't given an example here, but theoretically I could add a pre-request script which tests the current (non-blank) access_token against the API and, if it fails, get a new one using the given (non-blank) refresh_token. This would make it so I wouldn't have to worry about access tokens expiring.

That all said, I am not fond of this solution because it requires adding this first access_token call to every sub-folder in my collection because if I want to run a sub-folder only and not the collection as a whole, I need to make sure I have a fresh access_token. Not doing so would mean all tests would fail when an access_token expires. If you never run sub-folders separately in your Collection Runner, you could get away with only creating one access_token call and setting it as the first call to run in the collection.

But, for that reason, I'm not going to mark this as the correct answer yet. I'm guessing there is a better answer than what I've come up with - ideally one where I do not have to duplicate the same access_token call/test into each sub-folder, but do get the benefit of automated, non-interactive tests with the flexibility of running a sub-folder by itself or the collection as a whole.

Solution 2

Ok, first enter your OAUTH token URL, click on the Body tab, and fill out these POST parameters: client_id, grant_type, username, password, override.

enter image description here

Then, click on the Test tab, enter this text and then press Send:

var data = JSON.parse(responseBody);
postman.setGlobalVariable("access_token", data.access_token);
postman.setGlobalVariable("refresh_token", data.refresh_token);

enter image description here

Then enter one of your application URLs, click on the Headers Tab, and enter a parameter Authorization with a value Bearer {{access_token}}. Then click on Send.

enter image description here

Voila!

Solution 3

First, read this answer from the thread. Now, consider this the second half of the question (based on the comments):

How do I use the refresh token?

  1. Create a new POST request (easiest to duplicate the request you created to procure the access_token).

enter image description here

  1. In the body, remove username and password. Replace grant_type with "refresh_token". Add refresh_token with the value "{{refresh_token}}", which is a reference to the variable that got created when you first authorized (did you remember to read this answer?)

enter image description here

  1. Ensure your Tests section of the Refresh request overwrites the Postman variables for access_token and refresh_token. Why? Because whenever you execute a refresh, you'll get yet another refresh token. If you don't capture that new refresh token, you'll end up using the old refresh token and the API will reject it. Then you'll need to re-run the whole thing again from step one (i.e. from this answer).

enter image description here

  1. Now when your authorization expires, you don't need to run the original request that contains your username and password. You can perpetually refresh using the request we just created. This is especially helpful when you are collaborating and need to share API access, but don't want to share username/passwords.

HTH!

Solution 4

Both the other answers are correct. But, there is another way by which this can be done and does not require any extra request. This method uses the pre-request script of the request which needs the access_token. You can use the pm.sendRequest as documented in the postman-sandbox-api

From the pre-request script just send a request to the auth-token URL. Send all the credentials and the refresh token. In the response you will get the access token, which you can then persist in the environment or just in-memory and then use it.

Sample code I have made a gist here https://gist.github.com/harryi3t/dd5c61451206047db70710ff6174c3c1

// Set all these variables in an environment or at collection level
let tokenUrl = pm.variables.get('tokenUrl'),
    clientId = pm.variables.get('clientId'),
    clientSecret = pm.variables.get('clientSecret'),
    refreshToken = pm.variables.get('refreshToken'),
    requestOptions = {
      method: 'POST',
      url: tokenUrl,
      body: {
        mode: 'formdata',
        formdata: [
            {
                key: 'grant_type',
                value: 'refresh_token'
            },
            {
                key: 'client_id',
                value: clientId
            },
            {
                key: 'client_secret',
                value: clientSecret
            },
            {
                key: 'refresh_token',
                value: refreshToken
            }
        ]
      }
    };

console.log({ requestOptions });

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

  console.log({ err, jsonResponse, newAccessToken })

  // If you want to persist the token
  pm.environment.set('accessToken', newAccessToken);

  // Or if you just want to use this in the current request and then discard it
  pm.variables.set('accessToken', newAccessToken);
});

Now when the request is being sent, the variable accessToken will be present, which you can use in your request like this: enter image description here

Note: There are 4 types of Grant Types in Oauth2. Two of them (Auth code & Implicit) requires interaction with the browser which can't be automated. But if the server provides refresh-token then the above script can help you get the access-token. The other two types (client credentials & password credentials) doesn't require any browser interaction. So these can be automated from the scripts. If you are using client_credentials, you can tweak the above script to get the code from the authUrl and then get the access_token from AuthTokenUrl.

Share:
39,267
Nate Ritter
Author by

Nate Ritter

Web chef

Updated on January 12, 2021

Comments

  • Nate Ritter
    Nate Ritter over 3 years

    The goal

    Be able to run a collection without going through the authorization process of every call individually prior to running the collection.

    What I've attempted/noticed

    1. When using the OAuth2 authorization helper in Postman, I haven't discovered a method to save a returned refresh token, and thus use it when the access token expires to get a new one. (I've suggested this feature be placed into the helper in the Postman Github Issues.)

    2. I've tried creating a few steps at the beginning of the collection to replicate the helper, but cannot get past the step where user interaction is required to approve/deny (which makes sense as it's a security risk otherwise). However, I can't seem to figure out how to prompt the user either, the way the OAuth2 helper does.

    3. I've taken my expectations down a notch in regards to the refresh token and thought I could simply run the authentication on the first test in the list, saving the access token somehow in a global or environment variable, and then using that token in the all subsequent tests, but I have not found a way to save the access token generated via the OAuth2 helper.

    I would love to know if there is a solution to this which results in collections being able to be run with minimal effort put into authorization. This becomes more important with the more tests written in a collection which all use OAuth2 authorization.

    Side note: I've been using the Postman mac client, in case there is a different in clients I'm unaware of.