Skip to content

Instantly share code, notes, and snippets.

@dinvlad
Last active April 11, 2024 02:57
Show Gist options
  • Star 25 You must be signed in to star a gist
  • Fork 16 You must be signed in to fork a gist
  • Save dinvlad/425a072c8d23c1895e9d345b67909af0 to your computer and use it in GitHub Desktop.
Save dinvlad/425a072c8d23c1895e9d345b67909af0 to your computer and use it in GitHub Desktop.
Auto-generate Google Access and ID tokens from a Service Account key and save it in Postman
/* This script auto-generates a Google OAuth token from a Service Account key,
* and stores that token in accessToken variable in Postman.
*
* Prior to invoking it, please paste the contents of the key JSON
* into serviceAccountKey variable in a Postman environment.
*
* Then, paste the script into the "Pre-request Script" section
* of a Postman request or collection.
*
* The script will cache and reuse the token until it's within
* a margin of expiration defined in EXPIRES_MARGIN.
*
* Thanks to:
* https://paw.cloud/docs/examples/google-service-apis
* https://developers.google.com/identity/protocols/OAuth2ServiceAccount#authorizingrequests
* https://gist.github.com/madebysid/b57985b0649d3407a7aa9de1bd327990
* https://github.com/postmanlabs/postman-app-support/issues/1607#issuecomment-401611119
*/
const ENV_SERVICE_ACCOUNT_KEY = 'serviceAccountKey';
const ENV_JS_RSA_SIGN = 'jsrsasign';
const ENV_TOKEN_EXPIRES_AT = 'tokenExpiresAt';
const ENV_ACCESS_TOKEN = 'accessToken';
const JS_RSA_SIGN_SRC = 'https://kjur.github.io/jsrsasign/jsrsasign-latest-all-min.js';
const GOOGLE_OAUTH = 'https://www.googleapis.com/oauth2/v4/token';
// add/remove your own scopes as needed
const SCOPES = [
'https://www.googleapis.com/auth/userinfo.email',
'https://www.googleapis.com/auth/userinfo.profile',
];
const EXPIRES_MARGIN = 300; // seconds before expiration
const getEnv = name =>
pm.environment.get(name);
const setEnv = (name, value) =>
pm.environment.set(name, value);
const getJWS = callback => {
// workaround for compatibility with jsrsasign
const navigator = {};
const window = {};
let jsrsasign = getEnv(ENV_JS_RSA_SIGN);
if (jsrsasign) {
eval(jsrsasign);
return callback(null, KJUR.jws.JWS);
}
pm.sendRequest(JS_RSA_SIGN_SRC, (err, res) => {
if (err) return callback(err);
jsrsasign = res.text();
setEnv(ENV_JS_RSA_SIGN, jsrsasign);
eval(jsrsasign);
callback(null, KJUR.jws.JWS);
});
};
const getJwt = ({ client_email, private_key }, iat, callback) => {
getJWS((err, JWS) => {
if (err) return callback(err);
const header = {
typ: 'JWT',
alg: 'RS256',
};
const exp = iat + 3600;
const payload = {
aud: GOOGLE_OAUTH,
iss: client_email,
scope: SCOPES.join(' '),
iat,
exp,
};
const jwt = JWS.sign(null, header, payload, private_key);
callback(null, jwt, exp);
});
};
const getToken = (serviceAccountKey, callback) => {
const now = Math.floor(Date.now() / 1000);
if (now + EXPIRES_MARGIN < getEnv(ENV_TOKEN_EXPIRES_AT)) {
return callback();
}
getJwt(serviceAccountKey, now, (err, jwt, exp) => {
if (err) return callback(err);
const req = {
url: GOOGLE_OAUTH,
method: 'POST',
header: {
'Content-Type': 'application/x-www-form-urlencoded',
},
body: {
mode: 'urlencoded',
urlencoded: [{
key: 'grant_type',
value: 'urn:ietf:params:oauth:grant-type:jwt-bearer',
},{
key: 'assertion',
value: jwt,
}],
},
};
pm.sendRequest(req, (err, res) => {
if (err) return callback(err);
const accessToken = res.json().access_token;
setEnv(ENV_ACCESS_TOKEN, accessToken);
setEnv(ENV_TOKEN_EXPIRES_AT, exp);
callback();
});
});
};
const getServiceAccountKey = callback => {
try {
const keyMaterial = getEnv(ENV_SERVICE_ACCOUNT_KEY);
const serviceAccountKey = JSON.parse(keyMaterial);
callback(null, serviceAccountKey);
} catch (err) {
callback(err);
}
};
getServiceAccountKey((err, serviceAccountKey) => {
if (err) throw err;
getToken(serviceAccountKey, err => {
if (err) throw err;
});
});
@david-obadofin
Copy link

@dinvlad this worked! thanks

@juanrestrepo7716
Copy link

@dinvlad hello, thank you very much it was a great help, does anyone know how to implement this in angular?

@jgmsteinfeld
Copy link

Dinvlad, trying to use this and getting the following error:

GET https://kjur.github.io/jsrsasign/jsrsasign-latest-all-min.js
Error: unable to get local issuer certificate
Request Headers
User-Agent: PostmanRuntime/7.28.4
Accept: /
Postman-Token: 2496599a-8acd-4ed5-af6f-35b294062109
Host: kjur.github.io
Accept-Encoding: gzip, deflate, br
Connection: keep-alive

@dinvlad
Copy link
Author

dinvlad commented Sep 15, 2021

@jgmsteinfeld not sure tbh - it's working for me. Perhaps there's a problem with your certificates (or a temporary server-side problem)? If you're on Linux, you may need to install ca-certificates.

@jgmsteinfeld
Copy link

Thx Dinvlad. Let me give you a bit more context on this. I added my entire serviceAccountKey JSON to the parameter "serviceAccountKey" variable in an Environment tied to my request. The request I am making is to the "https://cloudasset.googleapis.com/v1/projects/<>:exportAssets" GCP API, but that is not happening as of yet as the error appears to be in the Pre-request Script. For Token I have this set to {{accessToken}} which I believe is correct.

@dinvlad
Copy link
Author

dinvlad commented Sep 16, 2021

@jgmsteinfeld I'm not sure tbh, everything seems to work fine on my end at least. As mentioned, it really does look like your Postman is missing some certificates and you may need to import them. Depending on your OS and if you're behind a corporate proxy, there might be a certificate bundle you may need to import - please see https://community.postman.com/t/unable-to-get-local-issuer-certificate-error/12323/5

@jgmsteinfeld
Copy link

@dinvlad Thank you very much the article told me where the issue was. I needed to turn off "SSL certificate verification" for making the GCP call. Now that error is gone. Thank you!. I did need to add the right scope for the API, but once done it worked like a charm. Thank you again.

@Totti10as
Copy link

Totti10as commented Sep 29, 2021

Hi @dinvlad,
I've following that instruction
section - Configuring Postman to use a pre-request script and service credentials.
and using your code but once trying to login got 403:
{
"error": {
"code": 403,
"message": "Request had insufficient authentication scopes.",
"errors": [
{
"message": "Insufficient Permission",
"domain": "global",
"reason": "insufficientPermissions"
}
],
"status": "PERMISSION_DENIED"
}
}

Scope:
// add/remove your own scopes as needed
const SCOPES = [
'https://mail.google.com/',
'https://www.googleapis.com/auth/userinfo.email',
'https://www.googleapis.com/auth/userinfo.profile',
'https://www.googleapis.com/auth/cloud-platform'

];

Could you please advice?

@dinvlad
Copy link
Author

dinvlad commented Sep 29, 2021

@Totti10as please see an earlier comment on how another user was able to get it working with GMail (and you need to enable domain-wide delegation for that service account).

@Totti10as
Copy link

Totti10as commented Sep 30, 2021

@Totti10as please see an earlier comment on how another user was able to get it working with GMail (and you need to enable domain-wide delegation for that service account).

I did both as @IGrimaylo and you @dinvlad suggested but now getting same error as @IGrimaylo describe above.

@dinvlad
Copy link
Author

dinvlad commented Sep 30, 2021

@Totti10as I'm not too sure then - if you could share a Gist with your modified code I could take a look, otherwise it might just "not work" with Gmail.. Google is more stringent with these APIs as they can be easily abused by machine accounts..

@dinvlad
Copy link
Author

dinvlad commented Sep 30, 2021

Also @Totti10as, the error clearly indicates the scopes are not sufficient. Could you confirm you're using GMail APIs, if and if so, which operation(s) are you trying to accomplish? I think you may need to add "https://www.googleapis.com/auth/gmail.modify" scope, if you haven't already.

@Totti10as
Copy link

Totti10as commented Oct 3, 2021

Also @Totti10as, the error clearly indicates the scopes are not sufficient. Could you confirm you're using GMail APIs, if and if so, which operation(s) are you trying to accomplish? I think you may need to add "https://www.googleapis.com/auth/gmail.modify" scope, if you haven't already.

@dinvlad i've added only one parameter to your script under the payload as is (other than that, nothing has changed, the token itself received properly and script seems to be work as expected ):
image

also the "https://www.googleapis.com/auth/gmail.modify" has been added as well under the scope
and the domain delegation activated:
image

and the request itself contains client email and not the service account;
https://gmail.googleapis.com/gmail/v1/users/{{gmailUserAcc}}/messages

i think it can cause the issue...
but in other hand I've tried to add the SA email in the request and still got same error (:

@Totti10as
Copy link

Totti10as commented Oct 3, 2021

@dinvlad
After all it seams that Gmail api does not support service accounts for non gsuite domains.
You can only use a service account with a Gsuite domain account and gsuite domain emails.

@dinvlad
Copy link
Author

dinvlad commented Oct 3, 2021

Thank you @Totti10as for digging into it! As suspected, GSuite is quite restrictive.

@NirajCricket
Copy link

Hi @dinvlad, I was searching for this article. thanks for uploading this.
However, postman has made some changes in variables that seem like.
I am trying to setup this to Googleapi via postman, and want to automate these tasks, as googleapis says to edit the remoteconfig, it needs a Service account. https://firebase.google.com/docs/remote-config/automate-rc#get_an_access_token_to_authenticate_and_authorize_api_requests.
I tried following your article , and I do got the JSON file from the service account, but as per google article,

  1. It says to have a admin permission for remote config to this SA, hence does it need to be in that role?
  2. second, can you confirm if we need the Environment to setup or if I just edit my collection and put variables in that collection, I did configure the variables in Env, but unable to call them in collection, whereas if I configure them in collection, I can see them:
    image

@dinvlad
Copy link
Author

dinvlad commented Oct 12, 2021

@NirajCricket not sure tbh, everything still works on my end I think. If it works with collections, great! You'd need to add Firebase Remote Config Admin role for your SA in any case, however.

@silvioangels
Copy link

Guys, i´m trying to call the Cloud functions service.
It´s giving to me the following error:

{
"message": "Jwt is not in the form of Header.Payload.Signature with two dots and 3 sections",
"code": 401
}

I just updated the scope variable to:
const SCOPES = [
'https://www.googleapis.com/auth/cloud-platform'
];

Do you have any idea of whats going on?

@dinvlad
Copy link
Author

dinvlad commented Oct 27, 2021

@silvioangels are you using idToken for your Bearer header to GCF?

@dinvlad
Copy link
Author

dinvlad commented Oct 27, 2021

and afaik you also would need to set a specific audience as explained here https://gist.github.com/dinvlad/425a072c8d23c1895e9d345b67909af0#gistcomment-3629784, but specific to GCF (depending on which JWT auth you're using for your GCF - either built-in IAM auth or Firebase Auth, the audiences will be different in each case).

@silvioangels
Copy link

silvioangels commented Oct 27, 2021

I changed now to idToken, but i don´t know what value can i set in the target_audience variable. Where can i found this?
I tried put the same url that i´m calling, but gives me the same 401 error.
I´ll put here the code, just to be sure that i´m setting the right code on "Pre-request Script" section:

/* This script auto-generates a Google OAuth token from a Service Account key,

const ENV_SERVICE_ACCOUNT_KEY = 'serviceAccountKey';
const ENV_JS_RSA_SIGN = 'jsrsasign';
const ENV_TOKEN_EXPIRES_AT = 'tokenExpiresAt';
const ENV_ACCESS_TOKEN = 'accessToken';

const JS_RSA_SIGN_SRC = 'https://kjur.github.io/jsrsasign/jsrsasign-latest-all-min.js';
const GOOGLE_OAUTH = 'https://www.googleapis.com/oauth2/v4/token';

// add/remove your own scopes as needed
const SCOPES = [
'https://www.googleapis.com/auth/cloud-platform'
];

const EXPIRES_MARGIN = 1; // seconds before expiration

const getEnv = name =>
pm.environment.get(name);

const setEnv = (name, value) =>
pm.environment.set(name, value);

const getJWS = callback => {
// workaround for compatibility with jsrsasign
const navigator = {};
const window = {};

let jsrsasign = getEnv(ENV_JS_RSA_SIGN);
if (jsrsasign) {
    eval(jsrsasign);
    return callback(null, KJUR.jws.JWS);
}

pm.sendRequest(JS_RSA_SIGN_SRC, (err, res) => {
    if (err) return callback(err);

    jsrsasign = res.text();
    setEnv(ENV_JS_RSA_SIGN, jsrsasign);
    eval(jsrsasign);
    callback(null, KJUR.jws.JWS);
});

};

const getJwt = ({ client_email, private_key }, iat, callback) => {
getJWS((err, JWS) => {
if (err) return callback(err);

    const header = {
        typ: 'JWT',
        alg: 'RS256',
    };

    const exp = iat + 3600;
    const payload = {
		target_audience: '<my url here>',
        aud: GOOGLE_OAUTH,
        iss: client_email,
        iat,
        exp,
    };

    const jwt = JWS.sign(null, header, payload, private_key);
    callback(null, jwt, exp);
});

};

const getToken = (serviceAccountKey, callback) => {
const now = Math.floor(Date.now() / 1000);
if (now + EXPIRES_MARGIN < getEnv(ENV_TOKEN_EXPIRES_AT)) {
return callback();
}

getJwt(serviceAccountKey, now, (err, jwt, exp) => {
    if (err) return callback(err);

    const req = {
        url: GOOGLE_OAUTH,
        method: 'POST',
        header: {
            'Content-Type': 'application/x-www-form-urlencoded',
        },
        body: {
          mode: 'urlencoded',
          urlencoded: [{
              key: 'grant_type',
              value: 'urn:ietf:params:oauth:grant-type:jwt-bearer',
          },{
              key: 'assertion',
              value: jwt,
          }],
        },
    };

    pm.sendRequest(req, (err, res) => {
        if (err) return callback(err);

        const accessToken = res.json().access_token;
        setEnv(ENV_ACCESS_TOKEN, accessToken);
        setEnv(ENV_TOKEN_EXPIRES_AT, exp);
		
		const idToken = res.json().id_token;
		setEnv("idToken", idToken);
		
        callback();
    });
});

};

const getServiceAccountKey = callback => {
try {
const keyMaterial = getEnv(ENV_SERVICE_ACCOUNT_KEY);
const serviceAccountKey = JSON.parse(keyMaterial);
callback(null, serviceAccountKey);
} catch (err) {
callback(err);
}
};

getServiceAccountKey((err, serviceAccountKey) => {
if (err) throw err;

getToken(serviceAccountKey, err => {
    if (err) throw err;
});

});

@silvioangels
Copy link

Wow @dinvlad i not change the bear token, now he give me the 403 error, i´m not understanding wha´s wrong :-\

{
"message": "Audiences in Jwt are not allowed",
"code": 403
}

@dinvlad
Copy link
Author

dinvlad commented Oct 27, 2021

@silvioangels if you're using IAM auth for your GCF (as it looks like), then the audience should be the URL of your function. You can read more about it here, and I suggest first invoking your function with a manually generated token as explained there: https://cloud.google.com/functions/docs/securing/authenticating

@dinvlad
Copy link
Author

dinvlad commented Oct 27, 2021

And if that doesn't work for you, try copy-pasting idToken to https://jwt.io, and comparing that to the manually generated token via gcloud auth print-identity-token.

@silvioangels
Copy link

silvioangels commented Oct 27, 2021

I got it. Our GCP Architect told us the autentication is this documentation:
https://developers.google.com/identity/protocols/oauth2/service-account?hl=en,
but he can´t provide a postman example of it (generating the bear token), if i use the gcloud comands ("auth activate-service-account --key-file" and "auth print-identity-token") i can call the GCF with the bear token.
i think the original pre_request.js that you did is the right way, but i´m trying here all options.
About generate the id_token, it´s blocked in GCF this way.

@dinvlad
Copy link
Author

dinvlad commented Oct 28, 2021

OK - if you can post the (masked) contents of your JWT payload (without headers/signature) both from this plugin and from print-identity-token, it would help understanding how it's different between these two.

@silvioangels
Copy link

@dinvlad it´s not a plugin, it´s the google sdk

@JSLadeo
Copy link

JSLadeo commented Dec 6, 2021

Hello , thanks a lot for this script, but for me it doesnt work.
I use for the scope : 'https://www.googleapis.com/auth/devstorage.read_only'.

My environment detail are:
image
detail of my service account key:
{"web":{"client_id":"---------.apps.googleusercontent.com",
"project_id":"------
",
"auth_uri":"https://accounts.google.com/o/oauth2/auth",
"token_uri":"https://oauth2.googleapis.com/token",
"auth_provider_x509_cert_url":"https://www.googleapis.com/oauth2/v1/certs",
"client_secret":"*************"}}

1st error: when i launch the request, i got an error " Cannot read property 'curve' of undefined", i think its cause of import "jsrsasign-latest-all-min.js" so i import before in another request

2nd error: After i import js rsa in my environment, i get an error in prescript but with no detail of the error...

If you can help me, can be awesome (it work well with manually token)

copy of the prescript :
const ENV_SERVICE_ACCOUNT_KEY = 'serviceAccountKey';
const ENV_JS_RSA_SIGN = 'jsrsasign';
const ENV_TOKEN_EXPIRES_AT = 'tokenExpiresAt';
const ENV_ACCESS_TOKEN = 'accessToken';

//const JS_RSA_SIGN_SRC = 'https://kjur.github.io/jsrsasign/jsrsasign-latest-all-min.js';
//const JS_RSA_SIGN_SRC = 'https://raw.githubusercontent.com/kjur/jsrsasign/master/jsrsasign-all-min.js';

const GOOGLE_OAUTH = 'https://www.googleapis.com/oauth2/v4/token';

// add/remove your own scopes as needed
const SCOPES = [
'https://www.googleapis.com/auth/devstorage.read_only'
];

const EXPIRES_MARGIN = 300; // seconds before expiration

const getEnv = name =>
pm.environment.get(name);

const setEnv = (name, value) =>
pm.environment.set(name, value);

const getJWS = callback => {
// workaround for compatibility with jsrsasign
const navigator = {};
const window = {};

let jsrsasign = getEnv(ENV_JS_RSA_SIGN);
if (jsrsasign) {
    eval(jsrsasign);
    return callback(null, KJUR.jws.JWS);
}

/*pm.sendRequest(JS_RSA_SIGN_SRC, (err, res) => {
    if (err) return callback(err);

    jsrsasign = res.text();
    setEnv(ENV_JS_RSA_SIGN, jsrsasign);
    eval(jsrsasign);
    callback(null, KJUR.jws.JWS);
});*/

};

const getJwt = ({ client_email, private_key }, iat, callback) => {
getJWS((err, JWS) => {
if (err) return callback(err);

    const header = {
        typ: 'JWT',
        alg: 'RS256',
    };

    const exp = iat + 3600;
    const payload = {
        aud: GOOGLE_OAUTH,
        iss: client_email,
        scope: SCOPES.join(' '),
        iat,
        exp,
    };

    const jwt = JWS.sign(null, header, payload, private_key);
    callback(null, jwt, exp);
});

};

const getToken = (serviceAccountKey, callback) => {
const now = Math.floor(Date.now() / 1000);
if (now + EXPIRES_MARGIN < getEnv(ENV_TOKEN_EXPIRES_AT)) {
return callback();
}

getJwt(serviceAccountKey, now, (err, jwt, exp) => {
    if (err) return callback(err);

    const req = {
        url: GOOGLE_OAUTH,
        method: 'POST',
        header: {
            'Content-Type': 'application/x-www-form-urlencoded',
        },
        body: {
          mode: 'urlencoded',
          urlencoded: [{
              key: 'grant_type',
              value: 'urn:ietf:params:oauth:grant-type:jwt-bearer',
          },{
              key: 'assertion',
              value: jwt,
          }],
        },
    };

    pm.sendRequest(req, (err, res) => {
        if (err) return callback(err);

        const accessToken = res.json().access_token;
        setEnv(ENV_ACCESS_TOKEN, accessToken);
        setEnv(ENV_TOKEN_EXPIRES_AT, exp);
        callback();
    });
});

};

const getServiceAccountKey = callback => {
try {
const keyMaterial = getEnv(ENV_SERVICE_ACCOUNT_KEY);
const serviceAccountKey = JSON.parse(keyMaterial);
callback(null, serviceAccountKey);
} catch (err) {
callback(err);
}
};

getServiceAccountKey((err, serviceAccountKey) => {
if (err) throw err;

getToken(serviceAccountKey, err => {
    if (err) throw err;
});

});

@dinvlad
Copy link
Author

dinvlad commented Dec 7, 2021

@JSLadeo that service account key looks very strange, how did you generate it? It needs to be generated using Google Cloud IAM Console or Google Cloud SDK.. https://cloud.google.com/iam/docs/creating-managing-service-account-keys

For example, mine look like this

{
  "client_email": "sa_name@project_id.iam.gserviceaccount.com",
  "client_id": "1234xxxxyyyyzzzzaaaabbbb",
  "private_key": "-----BEGIN PRIVATE KEY-----\n<REDACTED>\n-----END PRIVATE KEY-----\n",
  "private_key_id": "a1234567890abcdef1234567890abcdef>",
  "token_uri": "https://oauth2.googleapis.com/token",
  "type": "service_account"
}

@JSLadeo
Copy link

JSLadeo commented Dec 7, 2021

Hello , thx for your answer, got no error now, just 404 "No such object: -------remote-storage/--------.fic" . I work on it and tell you how it evolve

edit: probleme solve with good service account key.
Tanks a lot

@ffeldhaus
Copy link

ffeldhaus commented Aug 29, 2022

If the code is used for Google Cloud Platform it will not work as the GOOGLE_OAUTH constant is pointing to the wrong URI for Google Cloud tokens. At least in the case of Google Cloud Service Account keys, the token_uri field from the service account JSON should be used instead. Also the Google Cloud Scope should be added to make requests work. I have created an updated version of the gist here: https://gist.github.com/ffeldhaus/7753b24cf3631a9ddc1127e6fd835767

If someone can check if non Google Cloud Service Accounts also contain the token_uri then it should be updated in this gist.

@dinvlad
Copy link
Author

dinvlad commented Aug 29, 2022

Thanks @ffeldhaus - the original intent for this script is not to call Google Cloud APIs, but to call our own APIs with it. I know the latter is a bit of an anti-pattern, but that's what we used at my workplace (not my decision). Happy to see you got it working with GCP. I can incorporate your changes if you'd like, so we don't have to maintain separate versions - I think then it will work for either use case.

@ffeldhaus
Copy link

@dinvlad it would be great if you could merge the changes, maybe comment out the Google Cloud scope and just leave it as example. You did already a great job in coming up with this solution and I'll be glad to add something to make it work for even more users.

@johnchandlerbaldwin
Copy link

johnchandlerbaldwin commented Jun 30, 2023

Hi @dinvlad ,

I'm implementing this script for a project at work. Thanks so much for producing it. The script works fine when I run it manually, but when I try to run it on a schedule via the Postman Cloud I get a weird error. In the manual run, the accessToken and associated environment variable persist outside the pm.sendRequest function where they are generated. When I try to access those variables outside the function after the code has been run, however, my console.log statement says they are undefined and the code doesn't work - I get an auth error because the accessToken I passed in the body to Google Auth was undefined. Once again, this doesn't happen for manual runs of Postman in the app or in their web server, only when I schedule it to run on a regular basis.

Any idea what the problem could be? Let me know if you need any more information.

EDIT: It seems to be the same issue here: postmanlabs/newman#1825

I'm trying proposed solutions on the script and still can't get it to work. I tried timeOut around the pm.sendRequest and that didn't work. I'm going to try to use promises, but may need to review how they work before I get it to run. Any thoughts on how to get the script to work with this error would help, I'm far from an expert at Postman or javascript.

@dinvlad
Copy link
Author

dinvlad commented Jul 2, 2023

@johnchandlerbaldwin unfortunately no, I haven't tried Postman Cloud, and no ideas beyond what was suggested in those issues..

@johnchandlerbaldwin
Copy link

For sure. I was eventually able to get it to work by splitting out the pm.sendRequest statements into 2 individual requests. Then I was able to schedule it on Postman Cloud. In case anyone has this issue.

@mnikhil7692
Copy link

Thanks Denis (and everyone else as well ) for being so responsive to everyone's queries.
@johnchandlerbaldwin , just curious to see what did you actually mean when you said split the pm in 2 individual requests. Can you send an excerpt of those 2 splits ? I have a feeling i might be eventually going there

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment