Environment specific OAuth2 Authorization in Collections

My question: I’ve created a Collection and setup the Authorization to use OAuth2 - however this collection has requests that are designed to be used with a number of different environments, each environment with its own client_id and client_secret.

While I can parameterise the client_id and client_secret in the “Configure New Token” section, the access token has to be a specific value from the list of known tokens, so swapping between environments ends up using the same token (and doesn’t request a new one as the existing one from the original environment is still valid).

Is there anyway to parameterise the tokens themselves? Ultimately I’m looking to be able to run a request (which will automatically retrieve a token), change the environment, re-run the request (which will automatically retrieve another token for that environment) and have both requests execute with their appropriate tokens.

I recently put this pre-request script together to help me with my oauth requests in different environments.

You can set the Environment variables for each environment and it will appropriately use that oauth client/secret/token.

// OAUTH 2.0 Token Management Script 

/* 
 Checks for existing tokens and expiration, and will automatically update tokens if needed.

 Can be copy-pasted to other collections. This allows for using an Environment with different 
 OAuth client/secret and tokens for separate sources.

  Required variables for each collection using OAuth:
    Collection:
        "source": snake_case source name
    Environment:
        "{source}_client_id"
        "{source}_client_secret"
        "{source}_auth_url"
        "{source}_auth_scope"

 Returned variables if successful:
    Environment:
        "{source}_token_expiry"
        "{source}_access_token"

Example:

    Collection:
        "source": "azure"
    Environment:
        "azure_client_id"
        "azure_client_secret"
        "azure_auth_url"
        "azure_auth_scope"

 Returned variables if successful:
    Environment:
        "azure_token_expiry"
        "azure_access_token"

 Authorization for the collection needs to be Bearer Token.
 Token value needs to be {{{{source}}_access_token}}
 Requests in the collection should inherit auth from parent.
*/

// Static variables
const env = pm.collectionVariables.get("source");
const currentTime = Date.now();

// Environment variables
const tokenExpiry = pm.environment.get(`${env}_token_expiry`);
const accessToken = pm.environment.get(`${env}_access_token`);
const clientId = pm.environment.get(`${env}_client_id`);
const clientSecret = pm.environment.get(`${env}_client_secret`);
const requestUrl = pm.environment.get(`${env}_auth_url`);
const scope = pm.environment.get(`${env}_auth_scope`);
const missingVariables = !clientId || !clientSecret || !requestUrl || !scope;
const shouldUpdate = !tokenExpiry || !accessToken || (tokenExpiry <= currentTime);

if (missingVariables) {
    var missing = ""
    const required = new Map();
    required.set(`${env}_client_id`, clientId)
    required.set(`${env}_client_secret`, clientSecret)
    required.set(`${env}_auth_url`, requestUrl)
    required.set(`${env}_auth_scope`, scope)

    for (let [key, value] of required) {
        if (!value) {
            console.warn(`Missing environment variable ${key}`)
            missing += ` ${key} `
        }
    }
    throw ReferenceError(`Missing Required Environment Variables: ${missing}`)
}

if (shouldUpdate) {
    console.log("Retrieving new access token")
    pm.sendRequest({
        url: requestUrl,
        method: 'POST',
        header: {
            'Authorization': `Basic ${btoa(`${clientId}:${clientSecret}`)}`,
            'Content-Type': 'application/x-www-form-urlencoded',
            'Accept': 'application/json'
        },
        body: {
            mode: 'raw',
            raw: `grant_type=client_credentials&scope=${scope}`
        }
    }, function (err, response) {
        if (err) {
            console.warn("Token request failed");
            throw err;
        }

        const json = response.json();
        if (json.error) throw Error(`FAILED TO ACQUIRE ACCESS TOKEN.  ${json.error_description}`);

        pm.environment.set(`${env}_access_token`, json.access_token);
        pm.environment.set(`${env}_token_expiry`, currentTime + (json.expires_in * 1000));
    });
}

I hope this helps!

That’s a rather excellent script, though I was hoping that Postman had an out-of-the-box solution to what seems like a common set of functionality - using Environments and Authorization together - but if there isn’t a better way, I’m going to steal your script :slight_smile:

Thanks mate.