Search code examples
google-cloud-platformgoogle-cloud-functionsservice-accountsgoogle-iamgoogle-cloud-tasks

Cloud Functions / Cloud Tasks UNAUTHENTICATED error


I am trying to get a Cloud Function to create a Cloud Task that will invoke a Cloud Function. Easy.

The flow and use case are very close to the official tutorial here.

I also looked at this article by Doug Stevenson and in particular its security section.

No luck, I am consistently getting a 16 (UNAUTHENTICATED) error in Cloud Task.

enter image description here

If I can trust what I see in the console it seems that Cloud Task is not attaching the OIDC token to the request:

enter image description here

Yet, in my code I do have the oidcToken object:

const { v2beta3, protos } = require("@google-cloud/tasks");
import {
  PROJECT_ID,
  EMAIL_QUEUE,
  LOCATION,
  EMAIL_SERVICE_ACCOUNT,
  EMAIL_HANDLER,
} from "./../config/cloudFunctions";


export const createHttpTaskWithToken = async function (
  payload: {
    to_email: string;
    templateId: string;
    uid: string;
    dynamicData?: Record<string, any>;
  },
  {
    project = PROJECT_ID,
    queue = EMAIL_QUEUE, 
    location = LOCATION, 
    url = EMAIL_HANDLER, 
    email = EMAIL_SERVICE_ACCOUNT,
  } = {}
) {
  const client = new v2beta3.CloudTasksClient();
  const parent = client.queuePath(project, location, queue);

  // Convert message to buffer.
  const convertedPayload = JSON.stringify(payload);
  const body = Buffer.from(convertedPayload).toString("base64");

  const task = {
    httpRequest: {
      httpMethod: protos.google.cloud.tasks.v2.HttpMethod.POST,
      url,
      oidcToken: {
        serviceAccountEmail: email,
        audience: new URL(url).origin,
      },
      headers: {
        "Content-Type": "application/json",
      },
      body,
    },
  };


  try {
    // Send create task request.
    const request = { parent: parent, task: task };
    const [response] = await client.createTask(request);
    console.log(`Created task ${response.name}`);
    return response.name;
  } catch (error) {
    if (error instanceof Error) console.error(Error(error.message));
    return;
  }
};

When logging the task object from the code above in Cloud Logging I can see that the service account is the one that I created for the purpose of this and that the Cloud Tasks are successfully created.

Logs

IAM: enter image description here

And the function that the Cloud Task needs to invoke:

Function to invoke

Everything seems to be there, in theory.

Any advice as to what I would be missing?

Thanks,


Solution

  • Your audience is incorrect. It must end by the function name. Here, you only have the region and the project https://<region>-<projectID>.cloudfunction.net/. Use the full Cloud Functions URL.