Skip to content

Instantly share code, notes, and snippets.

Embed
What would you like to do?
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;
});
});
@SheikSena

This comment has been minimized.

Copy link

@SheikSena SheikSena commented Jul 9, 2020

@dinvlad, I tried by using the above-mentioned code to auto-generate the oath2 token using a service account. But it's not working. Can u provide the steps on how to do auto-generate the token?

@dinvlad

This comment has been minimized.

Copy link
Owner Author

@dinvlad dinvlad commented Jul 9, 2020

@SheikSena could you please elaborate a bit on what is not working? If you could share any error logs/messages, that would be helpful. Also, please outline the steps that you've taken so far. Thanks!

@CorvoMX

This comment has been minimized.

Copy link

@CorvoMX CorvoMX commented Jul 12, 2020

hi @dinvlad im very new on postman and google api and im getting this error:

There was an error in evaluating the Pre-request Script: JSONError: Unexpected token u in JSON at position 0

can you help me?

@dinvlad

This comment has been minimized.

Copy link
Owner Author

@dinvlad dinvlad commented Jul 15, 2020

Hi folks - have you followed all of the steps at the beginning of the file?

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.

@dinvlad

This comment has been minimized.

Copy link
Owner Author

@dinvlad dinvlad commented Jul 15, 2020

In particular, have you set serviceAccountKey variable in the Postman environment? (You need to create an environment first for all the other steps to work)

@CorvoMX

This comment has been minimized.

Copy link

@CorvoMX CorvoMX commented Jul 15, 2020

Hi @dinvlad yes, im not sure if i need to paste the key in a specific way (like remove the BEGIN OF THE KEY or something.
Captura de Pantalla 2020-07-15 a la(s) 9 29 51
Captura de Pantalla 2020-07-15 a la(s) 9 30 03

@dinvlad

This comment has been minimized.

Copy link
Owner Author

@dinvlad dinvlad commented Jul 15, 2020

Ok, so it needs to be pasted in JSON form, not in PEM (raw key form). Have you tried that?

@CorvoMX

This comment has been minimized.

Copy link

@CorvoMX CorvoMX commented Jul 15, 2020

Hello again @divlad

I tried to paste all the content

{
"type": "service_account",
"project_id": "drive-xxxxx",
"private_key_id": "xxxxxxxx",
"private_key":xxxxxx;
"client_email": "xxx@dxxxxx.gserviceaccount.com",
"client_id": "1111111111111111111",
"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_x509_cert_url": "https://www.googleapis.com/robot/v1/metadata/xxxxxxxxx.iam.gserviceaccount.com"
}

just this

"private_key_id": "xxxxxxxx",
"private_key":xxxxxx;

and just this

"private_key":xxxxxx;

and im still getting the same error.

@dinvlad

This comment has been minimized.

Copy link
Owner Author

@dinvlad dinvlad commented Jul 15, 2020

Ok, could you check that serviceAccountKey variable name is without {{ }} ?

@CorvoMX

This comment has been minimized.

Copy link

@CorvoMX CorvoMX commented Jul 15, 2020

Hi @dinvlad, its working thanks.

But in the response in getting

{
"error": {
"errors": [
{
"domain": "usageLimits",
"reason": "dailyLimitExceededUnreg",
"message": "Daily Limit for Unauthenticated Use Exceeded. Continued use requires signup.",
"extendedHelp": "https://code.google.com/apis/console"
}
],
"code": 403,
"message": "Daily Limit for Unauthenticated Use Exceeded. Continued use requires signup."
}
}

@dinvlad

This comment has been minimized.

Copy link
Owner Author

@dinvlad dinvlad commented Jul 15, 2020

Great! Is that a particular Google API that you're trying to call via Postman with this SA?

@CorvoMX

This comment has been minimized.

Copy link

@CorvoMX CorvoMX commented Jul 15, 2020

Hello @dinvlad, yes this one
https://www.googleapis.com/drive/v3/files

i added to the scopes

// add/remove your own scopes as needed
const SCOPES = [
'https://www.googleapis.com/auth/userinfo.email',
'https://www.googleapis.com/auth/userinfo.profile',
'https://www.googleapis.com/drive/v3/files',

];

@IGrimaylo

This comment has been minimized.

Copy link

@IGrimaylo IGrimaylo commented Nov 3, 2020

Hello! Im gettin error:
{ "error": { "code": 400, "message": "Precondition check failed.", "errors": [{ "message": "Precondition check failed.", "domain": "global", "reason": "failedPrecondition" }], "status": "FAILED_PRECONDITION" } }

what does it mean? And how can I fix it?

@dinvlad

This comment has been minimized.

Copy link
Owner Author

@dinvlad dinvlad commented Nov 3, 2020

@IGrimaylo could you give a bit more context, which steps have you followed and which APIs you're calling? Thanks

@IGrimaylo

This comment has been minimized.

Copy link

@IGrimaylo IGrimaylo commented Nov 4, 2020

Sorry. Im calling Gmail APIs, https://developers.google.com/gmail/api/reference/rest/v1/users.messages/list
Your script works, I received a token, but when I send a request, I get this error

@dinvlad

This comment has been minimized.

Copy link
Owner Author

@dinvlad dinvlad commented Nov 5, 2020

@IGrimaylo I see. It looks like maybe that particular request requires the email address of the API caller (a service account in this case) to match the email address of the user you're trying to list messages for. Hence, this error says there's a mismatch, so this is not possible, it seems :/. More on this here: https://stackoverflow.com/questions/62846906/httperror-400-precondition-check-failed-during-users-messages-list-gmail-api

@IGrimaylo

This comment has been minimized.

Copy link

@IGrimaylo IGrimaylo commented Nov 10, 2020

Hi! I resolved my problem. I use email from G Suite and transfer it to payload:
const payload = { aud: GOOGLE_OAUTH, sub: EMAIL, iss: client_email, scope: SCOPES.join(' '), iat, exp, };

Thank you!))

@dinvlad

This comment has been minimized.

Copy link
Owner Author

@dinvlad dinvlad commented Nov 10, 2020

That's interesting, thanks for letting me know! How were you able to "establish trust" between your service account and Gmail? Since it looks like you're able to list your Gmail messages with your Service Account, correct?

EDIT: I see, did you set SA to have domain-wide delegation? Makes sense :-)

@david-obadofin

This comment has been minimized.

Copy link

@david-obadofin david-obadofin commented Jan 14, 2021

@dinvlad Hi! Any ideas how I would modify this to also get the ID token. Im attempting to access an authenticated cloud run service and it requires I pass the ID token instead of the Access token.

I did some research and I found this response that suggests the scope determines if id_token is passed, however it didn't work.
https://community.auth0.com/t/oauth-token-not-returning-id-token/8303

@sehagens

This comment has been minimized.

Copy link

@sehagens sehagens commented Feb 4, 2021

Hi @dinvlad, I keep getting an error 403: "The caller does not have permission" when running your code. I followed your steps, tried it with several newly created Service Accounts, gave them domain-wide delegation, created new keys for them, disabled and enabled the APIs again. I also tried @IGrimaylo 's addition, but with no effect.
Once I run your code, the jsrsasign, accessToken and tokenExpiresAt variables are created and populated with (what looks like) correct data, but the 403 error persists.

I think I'm missing something, do you perhaps have any pointers or tips?

@dinvlad

This comment has been minimized.

Copy link
Owner Author

@dinvlad dinvlad commented Feb 4, 2021

@sehagens could you describe a bit more on which Google APIs you're trying it with?

@sehagens

This comment has been minimized.

Copy link

@sehagens sehagens commented Feb 4, 2021

@dinvlad I’m trying to fetch a certain range from a Google Spreadsheet so I used the Google Sheets API. As scopes I used https://www.googleapis.com/auth/drive and /auth/spreadsheets

@dinvlad

This comment has been minimized.

Copy link
Owner Author

@dinvlad dinvlad commented Feb 4, 2021

OK, interesting! Unfortunately, I don't have much experience with those (only used this for Google Cloud APIs..), so you may need to experiment for a little bit 😉

@abu-sithik

This comment has been minimized.

Copy link

@abu-sithik abu-sithik commented Feb 7, 2021

Hi @dinvlad, I am getting this error:
{
"error": {
"code": 400,
"message": "Precondition check failed.",
"errors": [
{
"message": "Precondition check failed.",
"domain": "global",
"reason": "failedPrecondition"
}
],
"status": "FAILED_PRECONDITION"
}
}

Tried to access Gmail APIs using ur script. Used this scope "https://www.googleapis.com/auth/gmail.modify"
Could u pls help me with why I am getting this error?

@dinvlad

This comment has been minimized.

Copy link
Owner Author

@dinvlad dinvlad commented Feb 8, 2021

@abu-sithik Yea it's a scopes issue like others have posted above! Please see https://gist.github.com/dinvlad/425a072c8d23c1895e9d345b67909af0#gistcomment-3378396

If you've tried that already, then not sure what else needs to be done - which API call are you trying to access?

@tsilvius23

This comment has been minimized.

Copy link

@tsilvius23 tsilvius23 commented Feb 10, 2021

@dinvlad Appreciate any suggestions you may have.

The above script is returning the id_token rather than accessToken.

Image 2-10-21 at 11 40 AM

Request Headers
Content-Type: application/x-www-form-urlencoded
User-Agent: PostmanRuntime/7.26.10
Accept: /
Postman-Token: 0b594cb2-a62c-400c-8b66-a45830cedbba
Host: www.googleapis.com
Accept-Encoding: gzip, deflate, br
Connection: keep-alive
Content-Length: 987
Request Body
grant_type: "urn:ietf:params:oauth:grant-type:jwt-bearer"
assertion: "eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiJ9.eyJhdWQiOiJodHRwczovL3d3dy5nb29nbGVhcGlzLmNvbS9vYXV0aDIvdjQvdG9rZW4iLCJpc3MiOiJ0c3BwbC0zNjdAbXktcHJvamVjdC03NTY0OC10cy5pYW0uZ3NlcnZpY2VhY2NvdW50LmNvbSIsInNjb3BlIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vYXV0aC91c2VyaW5mby5lbWFpbCBodHRwczovL3d3dy5nb29nbGVhcGlzLmNvbS9hdXRoL3VzZXJpbmZvLnByb2ZpbGUgaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vYXV0aC9jb250YWN0cyBodHRwczovL3Blb3BsZS5nb29nbGVhcGlzLmNvbS92MS9wZW9wbGUvbWUvY29ubmVjdGlvbnMgaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vYXV0aC91c2VyaW5mby5wcm9maWxlIiwiaWF0IjoxNjEyOTc0MzY4LCJleHAiOjE2MTI5Nzc5Njh9.ay_KMXK_HISUYmtBxMDpcmM8tBzB1Mjt3KC3RRqDJWB83GJSJwz1mqWtXyId1LxNkZA3RKjm7A3TI471KIQK-uRQ_aaeO8DDUrUughRVkU_FzpgyPe6BSy5em6DR9Vq87jQZ5BD5B3vA8OwUwhPiGI8-vJ3B9j5gSOQBYCvpb4mP0yGNjfHjuv3BrDakHrz9xwwfelKlyF4VDbnU4tSFPMMk-oeY6oYkW8NxrAhUzRgV6_NXa9EWihSA_TWdkXxc71SBNltQl53UJum37TcqCBEzdRUDIoih6QAMFCRJdKzlA1A0ImN21lbcyaPH4XgavplnmMSClkLdsFVOXH2ZbA"
Response Headers
Content-Type: application/json; charset=UTF-8
Vary: Origin
Vary: X-Origin
Vary: Referer
Content-Encoding: gzip
Date: Wed, 10 Feb 2021 16:26:09 GMT
Server: scaffolding on HTTPServer2
Cache-Control: private
X-XSS-Protection: 0
X-Frame-Options: SAMEORIGIN
X-Content-Type-Options: nosniff
Alt-Svc: h3-29=":443"; ma=2592000,h3-T051=":443"; ma=2592000,h3-Q050=":443"; ma=2592000,h3-Q046=":443"; ma=2592000,h3-Q043=":443"; ma=2592000,quic=":443"; ma=2592000; v="46,43"
Transfer-Encoding: chunked
Response Body
{"id_token":"eyJhbGciOiJSUzI1NiIsImtpZCI6ImZkMjg1ZWQ0ZmViY2IxYWVhZmU3ODA0NjJiYzU2OWQyMzhjNTA2ZDkiLCJ0eXAiOiJKV1QifQ.eyJhdWQiOiJodHRwczovL3d3dy5nb29nbGVhcGlzLmNvbS9hdXRoL3VzZXJpbmZvLmVtYWlsLGh0dHBzOi8vd3d3Lmdvb2dsZWFwaXMuY29tL2F1dGgvdXNlcmluZm8ucHJvZmlsZSxodHRwczovL3d3dy5nb29nbGVhcGlzLmNvbS9hdXRoL2NvbnRhY3RzLGh0dHBzOi8vcGVvcGxlLmdvb2dsZWFwaXMuY29tL3YxL3Blb3BsZS9tZS9jb25uZWN0aW9ucyxodHRwczovL3d3dy5nb29nbGVhcGlzLmNvbS9hdXRoL3VzZXJpbmZvLnByb2ZpbGUiLCJhenAiOiJ0c3BwbC0zNjdAbXktcHJvamVjdC03NTY0OC10cy5pYW0uZ3NlcnZpY2VhY2NvdW50LmNvbSIsImVtYWlsIjoidHNwcGwtMzY3QG15LXByb2plY3QtNzU2NDgtdHMuaWFtLmdzZXJ2aWNlYWNjb3VudC5jb20iLCJlbWFpbF92ZXJpZmllZCI6dHJ1ZSwiZXhwIjoxNjEyOTc3OTY5LCJpYXQiOjE2MTI5NzQzNjksImlzcyI6Imh0dHBzOi8vYWNjb3VudHMuZ29vZ2xlLmNvbSIsInN1YiI6IjEwMzY3Njg1NDEzMDk4MTkwMjEwOCJ9.ibApAAbtc44CdeTETZX5G3-zlIMAp6MeitpqaKGRnZl1pfokw8tc9BXkU8tYNvD5eMLc0GfOyAhDhNA3eJP4zAIjBeBag-TkbDmDJXZt_ypuMSIkJ2G6LmSvxa8mkAAHqorKGbi54Jzb9x6NQgZYchCAbMmxyjxXmf3w_kSNHY2CLXzK2WDgyCeQAtL966DkwJG5al9xPq1Aon6RjDKo37woITAu7I5QRr8cAYzUkHTAacAeID0WMMm16Wz8tyPKGaFURtk8Y6xGDpSzSHmaCANilk4ClMZz31smwKDFtSg-WEIUqcK3rxOcKtARBF4PJwCeSdyHELehSWN478pfzw"}

@dinvlad

This comment has been minimized.

Copy link
Owner Author

@dinvlad dinvlad commented Feb 10, 2021

@tsilvius23 That's strange, it works for me! Did you modify the script in any way?

@david-obadofin

This comment has been minimized.

Copy link

@david-obadofin david-obadofin commented Feb 12, 2021

@dinvlad Hi! Any ideas how I would modify this to also get the ID token. Im attempting to access an authenticated cloud run service and it requires I pass the ID token instead of the Access token.

I did some research and I found this response that suggests the scope determines if id_token is passed, however it didn't work.
https://community.auth0.com/t/oauth-token-not-returning-id-token/8303

Hi @dinvlad any thoughts on this?

@dinvlad

This comment has been minimized.

Copy link
Owner Author

@dinvlad dinvlad commented Feb 12, 2021

@david-obadofin ah right, so you can completely skip the access_token generation part because the script already generates a JWT for the service account first, and then uses that JWT to obtain access token. So just take the JWT and that will be your id_token.

@dinvlad

This comment has been minimized.

Copy link
Owner Author

@dinvlad dinvlad commented Feb 12, 2021

I've just updated the script to set a new idToken var in the environment. This way either could be used.

@dinvlad

This comment has been minimized.

Copy link
Owner Author

@dinvlad dinvlad commented Feb 12, 2021

Actually nevermind please, it's a bit more complicated than that. Cloud Run requires setting a particular audience for its tokens [1]. Your best bet is to modify the script to:

  1. set target_audience instead of aud claim in the requested JWT. It should be set to the URL of your Cloud Run app (instead of GOOGLE_OAUTH endpoint)
  2. exchange this JWT for a Google-signed ID token (I'm still figuring out how exactly to do this)

[1] https://cloud.google.com/run/docs/authenticating/service-to-service#calling-from-outside-gcp

@dinvlad

This comment has been minimized.

Copy link
Owner Author

@dinvlad dinvlad commented Feb 12, 2021

OK, I figured it out @david-obadofin:

  1. Add target_audience claim to the JWT payload (but keep the existing aud as-is!) and without scope:
const payload = {
  target_audience: 'https://your-app-xxxyyyzzz.a.run.app',
  aud: GOOGLE_OAUTH,
  iss: client_email,
  iat,
  exp,
};
  1. Read id_token instead of access_token from the response:
const idToken = res.json().id_token;
setEnv("idToken", idToken);
@david-obadofin

This comment has been minimized.

Copy link

@david-obadofin david-obadofin commented Feb 13, 2021

@dinvlad this worked! thanks

@juanrestrepo7716

This comment has been minimized.

Copy link

@juanrestrepo7716 juanrestrepo7716 commented May 6, 2021

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

@jgmsteinfeld

This comment has been minimized.

Copy link

@jgmsteinfeld jgmsteinfeld commented Sep 15, 2021

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

This comment has been minimized.

Copy link
Owner Author

@dinvlad 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

This comment has been minimized.

Copy link

@jgmsteinfeld jgmsteinfeld commented Sep 16, 2021

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

This comment has been minimized.

Copy link
Owner Author

@dinvlad 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

This comment has been minimized.

Copy link

@jgmsteinfeld jgmsteinfeld commented Sep 16, 2021

@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

This comment has been minimized.

Copy link

@Totti10as 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

This comment has been minimized.

Copy link
Owner Author

@dinvlad 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

This comment has been minimized.

Copy link

@Totti10as 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

This comment has been minimized.

Copy link
Owner Author

@dinvlad 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

This comment has been minimized.

Copy link
Owner Author

@dinvlad 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

This comment has been minimized.

Copy link

@Totti10as 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

This comment has been minimized.

Copy link

@Totti10as 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

This comment has been minimized.

Copy link
Owner Author

@dinvlad dinvlad commented Oct 3, 2021

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

@NirajCricket

This comment has been minimized.

Copy link

@NirajCricket NirajCricket commented Oct 12, 2021

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

This comment has been minimized.

Copy link
Owner Author

@dinvlad 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.

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