Authenticating service-to-service

Service-to-service authentication is the ability for one service, which can be a Cloud Run service, to invoke a Cloud Run service.

If your architecture is using multiple services, these services will likely need to communicate with each other.

You can use synchronous or asynchronous service-to-service communication:

For asynchronous communication, use

  • Cloud Tasks for one to one asynchronous communication
  • Pub/Sub for one to many asynchronous communication
  • Cloud Scheduler for regularly scheduled asynchronous communication.

For synchronous communication, one service invokes another one over HTTP using its endpoint URL. In this use case, it's a good idea to ensure that each service is only able to make requests to specific services. For instance, if you have a login service, it should be able to access the user-profiles service, but it probably shouldn't be able to access the search service.

First, you'll need to configure the receiving service to accept requests from the calling service:

  1. Grant the Cloud Run Invoker (roles/run.invoker) role to the calling service identity on the receiving service. By default, this identity is

Console UI

  1. Go to the Google Cloud Console:

    Go to Google Cloud Console

  2. Select the receiving service.

  3. Click Show Info Panel in the top right corner to show the Permissions tab.

  4. In the Add members field, enter the identity of the calling service.

  5. Select the Cloud Run Invoker role from the Select a role drop-down menu.

  6. Click Add.


Use the gcloud run services add-iam-policy-binding command:

gcloud run services add-iam-policy-binding RECEIVING_SERVICE \
  --member='serviceAccount:CALLING_SERVICE_IDENTITY' \

where RECEIVING_SERVICE is the name of the receiving service, and CALLING_SERVICE_IDENTITY is the email address of the service account.

In the calling service, you'll need to:

  1. Create a Google-signed OAuth ID token with the audience (aud) set to the URL of the receiving service. This value must contain the schema prefix (http:// or https://) and custom domains are currently not supported for the aud value.

  2. Include the ID token in an Authorization: Bearer ID_TOKEN header. You can get this token from the metadata server, while the container is running on Cloud Run. If the application is running outside Google Cloud, you can generate an ID token from a service account key file.

// Make sure to `npm install --save request-promise` or add the dependency to your package.json
const request = require('request-promise');

const receivingServiceURL = ...

// Set up metadata server request
// See
const metadataServerTokenURL = 'http://metadata/computeMetadata/v1/instance/service-accounts/default/identity?audience=';
const tokenRequestOptions = {
    uri: metadataServerTokenURL + receivingServiceURL,
    headers: {
        'Metadata-Flavor': 'Google'

// Fetch the token, then provide the token in the request to the receiving service
  .then((token) => {
    return request(receivingServiceURL).auth(null, null, true, token)
  .then((response) => {
  .catch((error) => {
# Requests is already installed, no need to add it to requirements.txt
import requests

receiving_service_url = ...

# Set up metadata server request
# See
metadata_server_token_url = 'http://metadata/computeMetadata/v1/instance/service-accounts/default/identity?audience='

token_request_url = metadata_server_token_url + receiving_service_url
token_request_headers = {'Metadata-Flavor': 'Google'}

# Fetch the token
token_response = requests.get(token_request_url, headers=token_request_headers)
jwt = token_response.content.decode("utf-8")

# Provide the token in the request to the receiving service
receiving_service_headers = {'Authorization': f'Bearer {jwt}'}
service_response = requests.get(receiving_service_url, headers=receiving_service_headers)

import (


// makeGetRequest makes a GET request to the specified Cloud Run endpoint in
// serviceURL (must be a complete URL) by authenticating with the ID token
// obtained from the Metadata API.
func makeGetRequest(serviceURL string) (*http.Response, error) {
	// query the id_token with ?audience as the serviceURL
	tokenURL := fmt.Sprintf("/instance/service-accounts/default/identity?audience=%s", serviceURL)
	idToken, err := metadata.Get(tokenURL)
	if err != nil {
		return nil, fmt.Errorf("metadata.Get: failed to query id_token: %+v", err)
	req, err := http.NewRequest("GET", serviceURL, nil)
	if err != nil {
		return nil, err
	req.Header.Add("Authorization", fmt.Sprintf("Bearer %s", idToken))
	return http.DefaultClient.Do(req)
This sample uses the Google Auth Library to retrieve application default credentials from your local development or remote Cloud Run environment. These credentials are used to create an ID token to append to the HTTP request.

public class Authentication {

  // makeGetRequest makes a GET request to the specified Cloud Run or
  // Cloud Functions endpoint, serviceUrl (must be a complete URL), by
  // authenticating with an Id token retrieved from Application Default Credentials.
  public static HttpResponse makeGetRequest(String serviceUrl) throws IOException {
    GoogleCredentials credentials = GoogleCredentials.getApplicationDefault();
    if (!(credentials instanceof IdTokenProvider)) {
      throw new IllegalArgumentException("Credentials are not an instance of IdTokenProvider.");
    IdTokenCredentials tokenCredential =
            .setIdTokenProvider((IdTokenProvider) credentials)

    GenericUrl genericUrl = new GenericUrl(serviceUrl);
    HttpCredentialsAdapter adapter = new HttpCredentialsAdapter(tokenCredential);
    HttpTransport transport = new NetHttpTransport();
    HttpRequest request = transport.createRequestFactory(adapter).buildGetRequest(genericUrl);
    return request.execute();

For an end-to-end walkthrough of an application using this service-to-service authentication technique, follow the securing Cloud Run services tutorial.

Calling from outside GCP

If you're invoking a service from a compute instance that doesn't have access to compute metadata (e.g. your own server), you'll have to manually generate the proper token:

  1. Self-sign a service account JWT with the target_audience claim set to the URL of the receiving service.

  2. Exchange the self-signed JWT for a Google-signed ID token, which should have the aud claim set to the above URL.

  3. Include the ID token in an Authorization: Bearer ID_TOKEN header in the request to the service.

You can examine the Identity-Aware Proxy sample code for code samples for the above steps.