From feac126c4939bf83b7f4f25dad1840da1ba66f5a Mon Sep 17 00:00:00 2001 From: Damion Murray Date: Sat, 21 Aug 2021 10:55:38 -0400 Subject: [PATCH] Updated library to support custom JWT header and signature encodings for Service Account authorization. --- src/Service.js | 16 +++++++++++++++- src/Utilities.js | 34 ++++++++++++++++++++++++++++------ 2 files changed, 43 insertions(+), 7 deletions(-) diff --git a/src/Service.js b/src/Service.js index 77ae4933..eda7225b 100644 --- a/src/Service.js +++ b/src/Service.js @@ -288,6 +288,20 @@ Service_.prototype.setAdditionalClaims = function(additionalClaims) { return this; }; +/** + * Sets custom JWT encoding options to use for Service Account authorization. + * @param {Object} customJWTEncodingOptions Custom JWT encoding options, as key-value pairs. + * @param {Object} [customJWTEncodingOptions.header] Custom JWT header properties + * @param {function} [customJWTEncodingOptions.computeJWTSignature] Custom function + * to compute JWT signature. + * @return {!Service_} This service, for chaining. + */ + Service_.prototype.setCustomJWTEncodingOptions = function(customJWTEncodingOptions) { + this.customJWTEncodingOptions_ = customJWTEncodingOptions; + return this; +}; + + /** * Sets the subject (sub) value to use for Service Account authorization. * @param {string} subject This subject value @@ -748,7 +762,7 @@ Service_.prototype.createJwt_ = function() { claimSet[key] = additionalClaims[key]; }); } - return encodeJwt_(claimSet, this.privateKey_); + return encodeJwt_(claimSet, this.privateKey_, this.customJWTEncodingOptions_); }; /** diff --git a/src/Utilities.js b/src/Utilities.js index 2daef62c..0cdd019d 100644 --- a/src/Utilities.js +++ b/src/Utilities.js @@ -96,24 +96,46 @@ function toLowerCaseKeys_(obj) { }, {}); } +/** + * Default method to compute JWT signature. + * + * @param {string} toSign String to Sign + * @param {string} key Key used to sign string + * @return {string} JWT Signature + */ +function computeJWTSignatureDefault_(toSign, key) { + var signatureBytes = + Utilities.computeRsaSha256Signature(toSign, key); + return Utilities.base64EncodeWebSafe(signatureBytes); +} + /* exported encodeJwt_ */ /** * Encodes and signs a JWT. * * @param {Object} payload The JWT payload. * @param {string} key The key to use when generating the signature. + * @param {Object} [customOptions] Options to customize JWT encoding + * @param {Object} [customOptions.header] Supply custom header properties + * @param {Function} [customOptions.computeJWTSignature] Custom function + * to compute JWT signature. * @return {string} The encoded and signed JWT. */ -function encodeJwt_(payload, key) { - var header = { +function encodeJwt_(payload, key, customOptions) { + var customOptions = customOptions || {}; + + var header = Object.assign({ alg: 'RS256', typ: 'JWT' - }; + }, customOptions.header || {}); + + var computeJWTSignature = typeof customOptions.computeJWTSignature === 'function' ? + customOptions.computeJWTSignature : computeJWTSignatureDefault_; + var toSign = Utilities.base64EncodeWebSafe(JSON.stringify(header)) + '.' + Utilities.base64EncodeWebSafe(JSON.stringify(payload)); - var signatureBytes = - Utilities.computeRsaSha256Signature(toSign, key); - var signature = Utilities.base64EncodeWebSafe(signatureBytes); + + var signature = computeJWTSignature(toSign, key); return toSign + '.' + signature; }