← Back to list

Locally test your Cloud Run service code that makes an authenticated call to another Cloud Run…

Previously I blogged about testing a Cloud Run service code locally that calls a Google Sheet. Reading and writing from a Google Sheet uses…

Sara Ford (Google) in Google Cloud - Community · 2026-06-30 05:32 · 7 claps · 2.5 min read
#google-cloud-run #serverless #gcp-app-dev #google-cloud-platform #gcp-security-operations
Open on Medium ↗
Wiki topics: ☁️ · DevOps & Cloud 📚 · Books & Reading

Locally test your Cloud Run service code that makes an authenticated call to another Cloud Run service

Cloud Run product logo

Cloud Run product logo

Previously I blogged about testing a Cloud Run service code locally that calls a Google Sheet. Reading and writing from a Google Sheet uses Google APIs, and that requires an OAuth Access Token. Just for the sake of completeness, I wanted to include the scenario where you’d use an ID Token (OIDC).

You’d use an ID Token whenever you’re making an authenticated call to a Cloud Run service that requires authorization.

A couple of points regarding the code below:

  • The Google Auth Library automatically generates an ID Token scoped specifically to that TARGET_URL. Remember not to include a slash at the end of the URL!! The Audience claim must match the Cloud Run service URL exactly, which does not include a trailing slash. Ask me how I know this 😅
  • The app puts the token in an Auth header and then makes the authenticated request.

requirements.txt

fastapi>=0.100.0
uvicorn>=0.22.0
google-auth>=2.22.0
requests>=2.34.2

main.py

import os
import urllib.request
from fastapi import FastAPI, HTTPException
import google.auth.transport.requests
import google.oauth2.id_token

# 1. FastAPI Application Setup
app = FastAPI()

# 2. Configuration
TARGET_URL = os.environ.get("TARGET_URL")

@app.get("/")
def call_authenticated_service():

# Fail fast if the configuration is missing or incorrectly formatted
if not TARGET_URL:
    raise ValueError("TARGET_URL environment variable is not set.")

if TARGET_URL.endswith("/"):
    raise ValueError(
        f"Invalid TARGET_URL: '{TARGET_URL}'. "
        "To match OAuth OIDC rules, the audience URL must not contain a trailing slash."
    )

    try:
        # Create a request object for the Google Auth library
        auth_req = google.auth.transport.requests.Request()

        # Fetch the OIDC ID token for the specific target audience
        target_token = google.oauth2.id_token.fetch_id_token(auth_req, TARGET_URL)

        # Build the request and attach the token
        req = urllib.request.Request(TARGET_URL)
        req.add_header("Authorization", f"Bearer {target_token}")

        # Execute the authenticated request
        with urllib.request.urlopen(req) as response:
            target_response_data = response.read().decode()

        return {
            "message": "Successfully authenticated and called target service.",
            "target_response": target_response_data
        }

    except Exception as e:
        raise HTTPException(status_code=500, detail=str(e))

Note re Terminology

You may be more familiar with the terms “assuming an identity” or “assuming the same permissions.” In Google Cloud, impersonating a service account lets an authenticated principal access whatever the service account can access. Only authenticated principals with the appropriate permissions can impersonate service accounts. You can read more here https://docs.cloud.google.com/iam/docs/service-account-overview#impersonation

How to configure your local environment

Similar to my previous post, you’ll impersonate the service account. You need to make sure your identity has the appropriate iam.serviceAccountTokenCreator role to generate tokens on behalf of the service account.

# Retrieve your current identity as shown in `gcloud auth list` 
YOUR_IDENTITY=$(gcloud config get-value account)

gcloud iam service-accounts add-iam-policy-binding $SERVICE_ACCOUNT_EMAIL \
    --member="user:$YOUR_IDENTITY" \
    --role="roles/iam.serviceAccountTokenCreator" \
    --project=$PROJECT_ID

Now configure ADC…

gcloud auth application-default login \
--impersonate-service-account=<YOUR_SERVICE_ACCOUNT_EMAIL>

and grant your SA the permissions to invoke the Cloud Run service.

gcloud run services add-iam-policy-binding <YOUR_SERVICE> \
 --member="serviceAccount:<YOUR_SERVICE_ACCOUNT>" \
 --role="roles/run.invoker" \
 --region="<YOUR_REGION>"

Let’s try it out locally!

Install your requirements locally, then start the service locally, passing in the URL for your Cloud Run service. For example, you could deploy the hello test image us-docker.pkg.dev/cloudrun/container/hello that requires authentication.

TARGET_URL=<YOUR_HELLO_CLOUD_RUN_SERVICE_URL> ./venv/bin/uvicorn main:app --reload

And now when you curl your endpoint, you will get the HTML for the Hello test container, e.g. <title>Congratulations | Cloud Run</title>

Deployment

Since you ran this locally, you’ll want to create a .gcloudignore file to avoid all your local dependencies being zipped up.

.gcloudignore

venv/

Now you’re ready to deploy with the service account as the identity to your Cloud Run service.

gcloud run deploy <YOUR_SERVICE_NAME> \
 --source . \
 --set-env-vars TARGET_URL=<YOUR_HELLO_CLOUD_RUN_SERVICE_URL> \
 --service-account <YOUR_SERVICE_ACCOUNT>

Now when you curl the Service URL in production, you’ll get the HTML for the hello test container.


메타데이터
post_id
6d56974de544
slug
locally-test-your-cloud-run-service-code-that-makes-an-authenticated-call-to-another-cloud-run-6d56974de544
url
https://medium.com/google-cloud/locally-test-your-cloud-run-service-code-that-makes-an-authenticated-call-to-another-cloud-run-6d56974de544
canonical_url
https://medium.com/google-cloud/locally-test-your-cloud-run-service-code-that-makes-an-authenticated-call-to-another-cloud-run-6d56974de544
author_url
https://medium.com/@saraford_5679
status
ok
fetched_at
2026-09-21 11:20:12