Generate code verifier & challenge for OAuth2 with PKCE using Google Apps Script

Here's how you can generate a cryptographically random code verifier, hash it using SHA256 & derive it's BASE64 encoded challenge in Google Apps Script.

Generate code verifier & challenge for OAuth2 with PKCE using Google Apps Script
Generate code verifier & challenge for OAuth2 with PKCE using Google Apps Script

Backstory

since the inception of my little side-project socials.so, i've had an increasing need to use Twitter's API at an alarmingly high rate and so thought to use it inside my existing Google Sheet / Apps Script workflow.

While Twitter has been famous for its continued use of OAuth1 — which seemed fairly complex, albeit doable within Apps Script — I started with the app only (bearer token) approach as that seemed pretty straight forward.

Within the initial few executions, I realised that one of the big drawbacks of this approach was the limited quota as it only allowed 300 requests every 15 minutes as opposed to 900 that's offered when "making requests on behalf of users" approach 🤦🏽‍♀️

When looking for samples in the OAuth2 for Apps Script library, i didn't find any from where i could simply copy>paste the code 😛 which is what rather motivated my lazy ass to create one from scratch.

You may recall from one of my previous post that i'd only very recently started using the OAuth2 ecosystem so this seemed exiting overall.

Code

feel free to make a copy of this script to see the sample code in action —

/**
 * Generate code_verifier & code_challenge for PKCE
 */
function pkceChallengeVerifier() {
  let verifier = "";
  // https://www.oauth.com/oauth2-servers/pkce/authorization-request/
  const possible = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-._~";
  for (let i = 0; i < 128; i++) {
    verifier += possible.charAt(Math.floor(Math.random() * possible.length));
  }
  console.log({verifier});

  const sha256Hash = Utilities.computeDigest(Utilities.DigestAlgorithm.SHA_256, verifier)
  const challenge = Utilities.base64Encode(sha256Hash)
    .replace(/\+/g, '-')
    .replace(/\//g, '_')
    .replace(/=+$/, '');
  console.log({challenge});
}

Usage

If you're curious to see this in action, head to Twitter.gs (yet to be added in the official OAuth2 Apps Script library) to experiment with it yourself 😇

Credits

It was most helpful to have the Online PKCE Generator Tool by Tony (Yihan) Xu as I was able to easily grab a few code verifier and challenge samples from the tool (which was initially tough for me to correctly generate, I'll admit 😅), use 'em as static values in my script to test whether or not its even possible to get done within Apps Script. once i had that, it was then easy (relatively) to simulate the same output in Apps Script.

Special mention: s/o to Steve Bazyl for rightfully pointing out not to take the easy way out with a weak implementation of PKCE (i'd originally just marked the code_challenge_method for my twitter sample code as plain hoping that no one would notice) 😛😅