I have been trying to automate the renewal of my FreeAgent OAuth Access Tokens whilst using Postman to develop my API requests. I am not a software developer. This has been difficult! The problems I am trying to solve are:
- Completely hands-off OAuth Access Token renewal automation in Postman
- Same automation for both sandbox and production environments
- Debug logging
The overall process is:
- Send an API request
- Check whether the current Access Token has expired
- If so, renew Access Token
- If not, continue with request
- Repeat
In order to achieve this automation, we need to:
- Create a Collection variable
- Create multiple Environment variables
- Create a Pre-request Script
- Authorise Postman via OAuth v2
*Note: this tutorial assumes that you have already created your app (e.g. Postman) via the Developer Dashboard and have you OAuth Identifier, OAuth Secret and Redirect URL. See dev docs.
In Postman:
1. Create a Collection variable
Create Collections for your sandbox and productions requests and add the following Collection variable to each:
VARIABLE: âResourceKeyâ, VALUE: {key}
This will be used to differentiate between FreeAgent sandbox and production environments e.g. âResourceKeyâ, âsandâ and âResourceKeyâ, âprodâ
2. Create multiple Environment variables
Create an Environment for FreeAgent and add the following Environment variables:
VARIABLE: âResource_{key}â, VALUE: {api endpoint}
This will be used to send token refresh requests e.g. âResource_sandâ, âhttps://api.sandbox.freeagent.com/â
VARIABLE: âClientIdâ, VALUE: {OAuth identifier}
This will be used to send token refresh requests e.g. âClientIdâ, âxxxxxxxxxxxxxxxxxxxxxxâ
VARIABLE: âClientSecretâ, VALUE: {OAuth secret}
This will be used to send token refresh requests e.g. âClientSecretâ, âxxxxxxxxxxxxxxxxxxxxxxâ
VARIABLE: âAccessToken_{key}â, VALUE: blank
This will store our AccessToken, will be used for all future API requests and will be automatically populated when we send our first request e.g. âAccessToken_sandâ, ââ
VARIABLE: âAccessTokenIss_{key}â, VALUE: blank
This will store when our Access Token was issued, will be used to check whether our Access Token has expired and will be automatically populated when we send our first request e.g. âAccessTokenIss_sandâ, ââ. Note: milliseconds since 01/01/1970.
VARIABLE: âAccessTokenExp_{key}â, VALUE: blank
This will store how long our Access Token has before it expires e.g. âAccessTokenExp_sandâ, ââ. Note: seconds.
VARIABLE: âRefreshToken_{key}â, VALUE: blank
This will store our Refresh Token, will be used to request new Access Tokens and will be automatically populated (note: initially, manually) when we send our first request e.g. âRefreshToken_sandâ, ââ.
3. Create a Pre-request Script
In your Collections, add the following to the Pre-request Script tab:
const key = pm.collectionVariables.get("ResourceKey");
if (!isAccessTokenExpired(key)) return;
if (!pm.environment.has(`RefreshToken_${key}`)) throw new Error(`Unable to find the refresh token with key "RefreshToken_${key}"`);
console.log(`Renewing the access token for the resource ${pm.environment.get(`Resource_${key}`)}`);
pm.sendRequest({
url: `${pm.environment.get(`Resource_${key}`)}v2/token_endpoint`,
method: 'POST',
header: {
'Accept': 'application/json',
'Content-Type': 'application/x-www-form-urlencoded'
},
body: {
mode: 'urlencoded',
urlencoded: [
{ key: "client_id", value: pm.environment.get("ClientId") },
{ key: "client_secret", value: pm.environment.get("ClientSecret") },
{ key: "redirect_uri", value: "https://oauth.pstmn.io/v1/callback" },
{ key: "grant_type", value: "refresh_token" },
{ key: "refresh_token", value: pm.environment.get(`RefreshToken_${key}`) }
]
}
}, function (err, res) {
if (err) {
throw err;
}
const token = res.json();
if (token.error) {
throw new Error(token.error);
}
pm.environment.set(`AccessToken_${key}`, token.access_token);
pm.environment.set(`AccessTokenExp_${key}`, token.expires_in);
pm.environment.set(`AccessTokenIss_${key}`, new Date().getTime());
pm.environment.set(`RefreshToken_${key}`, token.refresh_token);
console.log("The token was successfully renewed.");
});
function isAccessTokenExpired(key) {
if (!pm.environment.has(`AccessTokenIss_${key}`)) {
return true;
} else {
const issued = pm.environment.get(`AccessTokenIss_${key}`);
const expires = pm.environment.get(`AccessTokenExp_${key}`) * 1000;
const adjustment = 60 * 1000; // one minute
const expiresTime = issued + expires - adjustment;
const nowTime = new Date().getTime();
return nowTime > expiresTime;
}
}
Note: All credit for this script goes to Sergei Sergeev and his blog post: Configure Postman to be easily used with any Azure AD protected API (SharePoint, Graph, custom etc.), all I did was parameterise the Refresh Token request URL and modify how Access Token expiry checks occur.
4. Authorise Postman via OAuth
Now we need to get our first Access and Refresh Tokens for each Collection. In Collection > Authorization:
Type: OAuth 2.0
Add auth data to: Request Headers
Access Token: {{AccessToken_{{ResourceKey}}}}
Header Prefix: Bearer
Token Name: some name e.g. âAuth Token Sandâ
Grant Type: Authorization Code
Callback URL: check âAuthorise using browserâ
Auth URL: {{Resource_{{ResourceKey}}}}v2/approve_app
Access Token URL: {{Resource_{{ResourceKey}}}}v2/token_endpoint
Client ID: {{ClientId}}
Client Secret: {{ClientSecret}}
Scope: blank
State: blank
Client Authentication: Send as Basic Auth Header
Note: The variables should turn ORANGE, if they are RED, check for typos.
Click Get New Access Token
A default browser will open and the Authroization Grant will be processed, returning both Access and Refresh Tokens to Postman. If the popup is denied, enable popups and retry.
Manually store the Refresh Token in your RefreshToken_{key} Environment variables. This will be the last time you will ever have to do this.
CONCLUSION
The next time you send any request via Postman the Pre-request Script will run, it will notice that you donât have an Access Token issue time and automatically request a new Access Token. In doing so, its expiry time will be stored and then checked prior to all subsequent requests, and refreshed automatically if required.
Now you can play with the API without having to worry about refreshing your Access Tokens.