3

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.
7
  • 1
    I've generated a token using gcloud on my local machine and used it in my apps script, that works fine So, this implies that the token generated by apps script is incorrect? Commented Jun 2, 2020 at 4:32
  • Yes I think so. When I parse it using the online parser in [jwt.io] it says the signature is incorrect, so I'm guessing there's an issue with how appsscript does the signing Commented Jun 2, 2020 at 5:36
  • 1
    Does this answer your question? How can I authorize Google Speech-to-text from Google Apps script? Commented Jun 2, 2020 at 7:48
  • Its similar but not quite. This gives the Access Token. Cloud Requests ask for an Identity token which is in JWT format. Thing is I saw this solution amd even the docs say that you can get a JWT from it but didnt see where... Unless I missed something Commented Jun 2, 2020 at 21:57
  • 1
    See sample Commented Jun 3, 2020 at 4:20

1 Answer 1

2

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

Sign up to request clarification or add additional context in comments.

1 Comment

thanks! Can you please provide more details? What code you ended with? How did you set up Cloud Console? What Scopes were requied to connect?

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.