Skip to content

Instantly share code, notes, and snippets.

@jmehnle
Forked from dinvlad/pre_request.js
Last active December 1, 2021 01:11
Show Gist options
  • Save jmehnle/acec67853e5d833987759bd65f5bf72b to your computer and use it in GitHub Desktop.
Save jmehnle/acec67853e5d833987759bd65f5bf72b 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 the "access_token" variable in Postman.
*
* Prior to invoking it, set the following variables in a Postman environment:
* - "service_account_key": the contents of your service account key.
* - "scope": a space-separated list of Google API scopes, e.g.:
* "https://www.googleapis.com/auth/drive https://www.googleapis.com/auth/drive.metadata"
*
* Then, paste this 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 below.
*
* You can configure your Postman request or collection to use an
* authorization type of "Bearer Token" with a value of "{{access_token}}",
* and your requests will automatically authenticate.
*
* Thanks to:
* https://gist.github.com/dinvlad/425a072c8d23c1895e9d345b67909af0 (forked)
* 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 = 'service_account_key';
const ENV_JS_RSA_SIGN = 'src_jsrsasign';
const ENV_TOKEN_EXPIRES_AT = 'access_token_expires_at';
const ENV_ACCESS_TOKEN = 'access_token';
const ENV_SCOPE = 'scope';
const JS_RSA_SIGN_SRC = 'https://kjur.github.io/jsrsasign/jsrsasign-latest-all-min.js';
const GOOGLE_OAUTH = 'https://oauth2.googleapis.com/token';
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: getEnv(ENV_SCOPE),
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;
});
});
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment