I am trying to invoke an authenticated HTTP-based cloud function from another cloud function. Let's call them CF1 and CF2 respectively, for the sake of brevity; thus I wish to invoke CF2 from CF1.
Following the example given by the Google Documentation: Authenticating for Invocation, I created a new service account for CF2, and then attached it to CF1 with the roles/cloudfunctions.admin
. I downloaded a service key for local testing with Functions Framework, setting it as the Application Default Credentials(ADC); thus CF2 on my local machine connects to CF1 on GCP, authenticating as CF2's service account via ADC.
I have deployed CF1 on Cloud Functions successfully, and was testing whether CF2 on my local machine could reach to CF1 when I was surprised to receive a HTTP 401.
For reference, here is the code in question, which is almost identical to the samples provided by the Google Documentation:
String serviceUrl = "<cf1-url>";
GoogleCredentials credentials = GoogleCredentials.getApplicationDefault();
if (!(credentials instanceof IdTokenProvider)) {
throw new IllegalArgumentException("Credentials are not an instance of IdTokenProvider.");
}
IdTokenCredentials tokenCredential =
IdTokenCredentials.newBuilder()
.setIdTokenProvider((IdTokenProvider) credentials)
.setTargetAudience(serviceUrl)
.build();
GenericUrl genericUrl = new GenericUrl(serviceUrl);
HttpCredentialsAdapter adapter = new HttpCredentialsAdapter(tokenCredential);
HttpTransport transport = new NetHttpTransport();
com.google.api.client.http.HttpRequest request = transport.createRequestFactory(adapter).buildGetRequest(genericUrl);
com.google.api.client.http.HttpResponse response = request.execute();
I tried referring to:
but I was not able to find a solution to my problem from those questions.
Further testing revealed that the identity token generated via the client SDK:
tokenCredential.getIdToken().getTokenValue()
is different from the GCloud CLI command gcloud auth print-identity-token
. I could use the identity token generated by GCloud CLI to directly invoke CF1 (e.g. via Postman/cURL and authenticated as CF2's service account) but not the identity token printed by the client SDK. This was a surprise as I am using CF 2's service account keys as the ADC, and also authorized it for gcloud access via gcloud auth activate-service-account
.
It seems to me that there is no issue with the permissions of the service accounts and cloud functions, as I can directly invoke CF1; thus it would appear to be an issue with the code. However, I am unable to determine the cause of the 401 error.
The target audience, your serviceURL
, must be the raw url, this one provided by the Cloud Functions service.
If you add your parameters (query or path) it won't work.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With