简体   繁体   中英

How Do I Authenticate a Service Account via Apps Script in order to Call a GCP Cloud Function

I'm trying hell hard to run a GCP Cloud Function from Apps Script. The Cloud function requires Authentication. However I keep getting thrown a "401 Error"

On My Google Project;

  1. I've Created a Cloud function that requires Authentication
  2. I've Created a Service Account that has Invoke (and edit) access to that function
  3. I've Downloaded the JSON key for that service account and saved it as an object named CREDS in my Apps Script

This is my script so far:

const CREDS = {....JSON Key I downloaded from Cloud Console}

function base64Encode(str){
  let encoded = Utilities.base64EncodeWebSafe(str)

  return encoded.replace(/=+$/,'')
}

function encodeJWT(){
  const privateKey = `Copied the PK from the CREDs file and replaced all the escaped whitespace as a string literal`;

  let header = JSON.stringify({
    alg: "RS256",
    typ: "JWT",
  });

  let encodedHeader = base64Encode(header);

  const now = Math.floor(Date.now() / 1000);
  let payload = JSON.stringify({
    "iss": "https://accounts.google.com",
    "azp": "OAUTH CLIENT ID I CREATED ON GCP",
    "aud": "OAUTH CLIENT ID I CREATED ON GCP",
    "sub": CREDS.client_id,
    "email": CREDS.client_email,
    "email_verified": true,
    //    "at_hash": "TMTv8_OtKA539BBRxLoTBw", //Saw this in a reverse engineered Token but didnt know what to put
    "iat": now.toString(),
    "exp": (now + 3600).toString()  
  })

  let encodedPayload = base64Encode(payload);

  let toSign = [encodedHeader, encodedPayload].join('.')
  let signature = Utilities.computeRsaSha256Signature(toSign, privateKey)
  let encodedSignature = base64Encode(signature);

  let jwt = [toSign, encodedSignature].join('.')

  return jwt;

}

function testFireStore() {
  let funcUrl = "https://[MY PROJECT].cloudfunctions.net/MyFunc"

  const token = encodeJWT()
  let options = {
    headers:{
      "Authorization": "Bearer " + token
    }
  }


  let func = UrlFetchApp.fetch(funcUrl,options)
  Logger.log(func.getContentText())
}

The actual Cloud func just gives a "Hello World" for now and it tests fine in the console

FYI, some steps I've done already

  • I've generated a token using gcloud on my local machine and used it in my apps script, that works fine
  • I've taken the said token and reverse engineered it on https://jwt.io
  • I've used the code here to create my JWT function which I checked back with https://jwt.io to ensure its in the correct format.

This Solution posted by @TheMaster in the comments to my solution solved the issue.

On the GCP side, I went in and enabled compute Engine and App Engine, then used this solution and it worked.

The only odd thing is that the target_audience requested there, I had to do a bit of reverse engineering to get it. I had to get the Identity Token from the command line tool, then use jwt.io to decode it, getting the AUD key...

but that aside, everythign worked like a charm

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM