OAuth2 Workflow Improvement Suggestions

Hi ApiDog Team,

First off, I really appreciate the work you’ve done with ApiDog—it’s a great tool! However, I have a few suggestions that could significantly improve the OAuth2 authentication workflow, especially when using the client_credentials grant type.

1. Persistent Tokens per Environment

Currently, when switching between environments (e.g., local, staging, production), I need to manually click “Get Token” every time, even if the token is still valid. Since tokens often have a long lifespan (e.g., 6 hours), it would be great if ApiDog could:

  • Store and persist tokens per environment to avoid unnecessary refreshes.
  • Automatically use the correct token when switching environments, without requiring a manual refresh if the token is still valid.

2. Auto-Renew Tokens on 401/403 Responses

Right now, if a request fails due to an expired or invalid token (401/403), I need to manually fetch a new token. It would be awesome if ApiDog could:

  • Detect a 401/403 response and automatically call the IAM endpoint to refresh the token.
  • Optionally retry the original request after successfully retrieving a new token.
  • Provide an option to automatically refresh the token before it expires (based on expires_in).

3. Reducing Clicks for Short-Lifespan Tokens

I currently use a 5-minute token lifespan, which means I have to constantly:

  1. Click Get New Token
  2. Authenticate in the root folder
  3. Go back to my request
  4. Manually update auth again

This adds a lot of extra steps. A more streamlined approach would make development much smoother.

4. Example: My Current Pre-request Script

To work around these issues, I’m currently using the following pre-request script to fetch a new token when needed: *see 1first comment on topic

Would it be possible to implement a similar in ApiDog? It would improve the developer experience!

Thanks for considering these suggestions. Keep up the great work!

try {
  var [iamTokenUrl, clientId, clientSecret] =
    ["IAM_TOKEN_URL", "CLIENT_ID", "CLIENT_SECRET"].map(key => pm.environment.replaceIn(pm.environment.get(key)));

  var currentAccessToken = pm.environment.has("ACCESS_TOKEN") ? pm.environment.get("ACCESS_TOKEN") : null;
  var accessTokenExpires = pm.environment.get("ACCESS_TOKEN_EXPIRES");

  var hasAccessToken = currentAccessToken !== null;
  var isExpired = accessTokenExpires ? Date.now() >= accessTokenExpires : true;

  var needsTokenUpdate = !hasAccessToken || isExpired;

  function sendLoginRequest() {
    console.log('sendLoginRequest');
    pm.sendRequest({
      url: iamTokenUrl,
      method: "POST",
      body: {
        mode: "urlencoded",
        urlencoded: [
          { key: "grant_type", value: "client_credentials" },
          { key: "client_id", value: clientId },
          { key: "client_secret", value: clientSecret }
        ]
      }
    }, (err, res) => {
      if (err) return console.error("Login request failed:", err);

      const { access_token, expires_in } = res.json();
      pm.environment.set("ACCESS_TOKEN", access_token);
      pm.environment.set("ACCESS_TOKEN_EXPIRES", Date.now() + expires_in * 1000);
    });
  }

  if (needsTokenUpdate) {
    sendLoginRequest();
  }
} catch (e) {
  console.log(e);
}

Additionally, I handle 401/403 responses with this logic:

var statusCode = pm.response.code || 0;

if (statusCode === 401 || statusCode === 403) { 
  console.warn(`Received ${statusCode}. Removing ACCESS_TOKEN and retrying request...`);
  pm.environment.unset("ACCESS_TOKEN");
}