Last active
August 12, 2021 12:23
-
-
Save karthik2804/1f9adfc358d002ca3c184bd286dd77d2 to your computer and use it in GitHub Desktop.
Get Google Oauth2 Access Token
This file contains hidden or 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
| /* | |
| * Store the private key and email id of the service account as environment variables | |
| * PRIVATE_KEY - Service account private key | |
| * SERVICE_ACCOUNT_EMAIL - email id of the service account | |
| */ | |
| async function getToken(request) { | |
| try { | |
| // Function to encode an object with base64 | |
| function objectToBase64url(object) { | |
| return arrayBufferToBase64Url( | |
| new TextEncoder().encode(JSON.stringify(object)), | |
| ) | |
| } | |
| // Function to encode array buffer with base64 | |
| function arrayBufferToBase64Url(buffer) { | |
| return btoa(String.fromCharCode(...new Uint8Array(buffer))) | |
| .replace(/=/g, '') | |
| .replace(/\+/g, '-') | |
| .replace(/\//g, '_') | |
| } | |
| // Function to convert string to array buffer | |
| function str2ab(str) { | |
| const buf = new ArrayBuffer(str.length); | |
| const bufView = new Uint8Array(buf); | |
| for (let i = 0, strLen = str.length; i < strLen; i++) { | |
| bufView[i] = str.charCodeAt(i); | |
| } | |
| return buf; | |
| } | |
| // | |
| // Step 1 - Form the JWT header and encode to base64 | |
| const GOOGLE_JWT_HEADER = objectToBase64url({ | |
| // RSA SHA-256 algorithm is mandatory for Google | |
| alg: 'RS256', | |
| // JWT token format is mandatory for Google | |
| typ: 'JWT' | |
| }) | |
| // | |
| // Step 2 - Form the JWT claim set and encode to base64 | |
| // Define the time the assertion was issued | |
| let assertiontime = Math.round(Date.now() / 1000) | |
| // Define the expiration time of the assertion, maximum 1 hour | |
| let expirytime = assertiontime + 3600 | |
| // JWT claim payload | |
| const GOOGLE_JWT_CLAIMSET = objectToBase64url({ | |
| // Service account email address from https://console.cloud.google.com | |
| // This should be defined as a secret rather than hardcoded!! | |
| 'iss': SERVICE_ACCOUNT_EMAIL, | |
| // A listing of available scopes is provided here: | |
| // https://developers.google.com/identity/protocols/oauth2/scopes | |
| 'scope': 'https://www.googleapis.com/auth/spreadsheets', | |
| 'aud': 'https://oauth2.googleapis.com/token', | |
| 'exp': expirytime, | |
| 'iat': assertiontime | |
| }) | |
| // Combine the JWT header + claim and convert to byte array for signing | |
| const GOOGLE_JWT_COMBINED = str2ab( | |
| "{" + | |
| GOOGLE_JWT_HEADER + | |
| "}.{" + | |
| GOOGLE_JWT_CLAIMSET + | |
| "}" | |
| ) | |
| // | |
| // Step 3 - Sign the combined GOOGLE_JWT_HEADER and GOOGLE_JWT_CLAIMSET | |
| const PRIVATE_KEY = PRIVATE_KEY | |
| const private_key_raw = PRIVATE_KEY.replace(/\\n/g, "\n"); | |
| // Tidy up the key ahead of importing | |
| var private_key_clean = private_key_raw.replace('-----BEGIN PRIVATE KEY-----', ''); | |
| var private_key_clean = private_key_clean.replace('-----END PRIVATE KEY-----', ''); | |
| var private_key_clean = private_key_clean.replace(/(\r\n|\n|\r)/gm, ""); | |
| // base64 decode the string to get the binary data | |
| var private_key_binary = atob(private_key_clean); | |
| // convert from a binary string to an ArrayBuffer | |
| var private_key_binary = str2ab(private_key_binary); | |
| // Import the private key into the crypto store | |
| const SIGNING_KEY = await crypto.subtle.importKey( | |
| "pkcs8", | |
| private_key_binary, | |
| { | |
| name: "RSASSA-PKCS1-V1_5", | |
| hash: { name: "SHA-256" } | |
| }, | |
| false, | |
| ["sign"] | |
| ); | |
| // Sign the GOOGLE_JWT_HEADER and GOOGLE_JWT_CLAIMSET | |
| const rawToken = await crypto.subtle.sign( | |
| { name: 'RSASSA-PKCS1-V1_5' }, | |
| SIGNING_KEY, | |
| GOOGLE_JWT_COMBINED | |
| ); | |
| // Convert the signature to Base64URL format | |
| const GOOGLE_JWT_SIGNED = arrayBufferToBase64Url(rawToken); | |
| // Combine the headers with signature | |
| var combined_headers_signed = | |
| "{" + | |
| GOOGLE_JWT_HEADER + | |
| "}.{" + | |
| GOOGLE_JWT_CLAIMSET + | |
| "}.{" | |
| + GOOGLE_JWT_SIGNED + | |
| "}"; | |
| // | |
| // Step 4 - Send the request | |
| // Create payload | |
| const GOOGLE_JWT_PAYLOAD = | |
| "grant_type=" + | |
| "urn%3Aietf%3Aparams%3Aoauth%3Agrant-type%3Ajwt-bearer&assertion=" + | |
| combined_headers_signed; | |
| // Make the OAUTH request | |
| const response = await fetch('https://oauth2.googleapis.com/token', { | |
| method: 'POST', | |
| headers: { | |
| 'Content-Type': 'application/x-www-form-urlencoded', | |
| 'Cache-Control': 'no-cache', | |
| 'Host': 'oauth2.googleapis.com' | |
| }, | |
| body: GOOGLE_JWT_PAYLOAD | |
| }); | |
| const oauth = await response.json(); | |
| return oauth.access_token; | |
| } catch (err) { | |
| console.log(err) | |
| } | |
| } |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment