-
-
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 file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* 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