End user authentication for Cloud Run tutorial

This tutorial shows how to create a voting service, consisting of:

  • A browser-based client that:

    1. UsesIdentity Platform to fetch an ID token.
    2. Allows users to vote for their favorite domestic animal.
    3. Adds that ID token to a request to the Cloud Run server thatprocesses the vote.
  • A Cloud Run server that:

    1. Checks to make sure the end-user has properly authenticated by providinga valid ID token.
    2. Processes the end-user's vote.
    3. Using its own credentials, sends the vote on to Cloud SQL for storage.
  • A PostgreSQL database that stores the votes.

For simplicity, this tutorial uses Google as aprovider: users must authenticate usingtheir user account in order to acquire their ID token. However, you can useother providers or authentication methods tosign in users.

When this document uses the termuser account, it refers to a Google Account, or a user account managed by your identity provider and federated withWorkforce Identity Federation.

You use the credentials provided by your user account to sign in to the tool.

This service minimizes security risks by usingSecret Managerto protect sensitive data used to connect to the Cloud SQL instance. It alsouses aleast-privilege service identity tosecure access to the database.

Objectives

Write, build, and deploy a service to Cloud Run that shows how to:

  • Use Identity Platform to authenticate an end-user to theCloud Run service backend.

  • Create a least-privilege identity for the service to grantminimal access to Google Cloud resources.

  • Use Secret Manager to handle sensitive data when connectingthe Cloud Run service to a postgreSQL database.

Costs

In this document, you use the following billable components of Google Cloud:

To generate a cost estimate based on your projected usage, use thepricing calculator.

New Google Cloud users might be eligible for afree trial.

Before you begin

  1. Sign in to your Google Cloud account. If you're new to Google Cloud, create an account to evaluate how our products perform in real-world scenarios. New customers also get $300 in free credits to run, test, and deploy workloads.
  2. In the Google Cloud console, on the project selector page, select or create a Google Cloud project.

    Roles required to select or create a project

    • Select a project: Selecting a project doesn't require a specific IAM role—you can select any project that you've been granted a role on.
    • Create a project: To create a project, you need the Project Creator role (roles/resourcemanager.projectCreator), which contains theresourcemanager.projects.create permission.Learn how to grant roles.
    Note: If you don't plan to keep the resources that you create in this procedure, create a project instead of selecting an existing project. After you finish these steps, you can delete the project, removing all resources associated with the project.

    Go to project selector

  3. Verify that billing is enabled for your Google Cloud project.

  4. In the Google Cloud console, on the project selector page, select or create a Google Cloud project.

    Roles required to select or create a project

    • Select a project: Selecting a project doesn't require a specific IAM role—you can select any project that you've been granted a role on.
    • Create a project: To create a project, you need the Project Creator role (roles/resourcemanager.projectCreator), which contains theresourcemanager.projects.create permission.Learn how to grant roles.
    Note: If you don't plan to keep the resources that you create in this procedure, create a project instead of selecting an existing project. After you finish these steps, you can delete the project, removing all resources associated with the project.

    Go to project selector

  5. Verify that billing is enabled for your Google Cloud project.

  6. Enable the Cloud Run, Secret Manager, Cloud SQL, Artifact Registry, and Cloud Build APIs.

    Roles required to enable APIs

    To enable APIs, you need the Service Usage Admin IAM role (roles/serviceusage.serviceUsageAdmin), which contains theserviceusage.services.enable permission.Learn how to grant roles.

    Enable the APIs

Required roles

To get the permissions that you need to complete the tutorial, ask your administrator to grant you the following IAM roles on your project:

For more information about granting roles, seeManage access to projects, folders, and organizations.

You might also be able to get the required permissions throughcustom roles or otherpredefined roles.

Note:IAM basic roles might also contain permissions to complete the tutorial. You shouldn't grant basic roles in a production environment, but you can grant them in a development or test environment.

Setting upgcloud defaults

To configure gcloud with defaults for your Cloud Run service:

  1. Set your default project:

    gcloudconfigsetprojectPROJECT_ID

    ReplacePROJECT_ID with the name of the project you created forthis tutorial.

  2. Configure gcloud for your chosen region:

    gcloudconfigsetrun/regionREGION

    ReplaceREGION with the supported Cloud Runregionof your choice.

Cloud Run locations

Cloud Run is regional, which means the infrastructure thatruns your Cloud Run services is located in a specific region and ismanaged by Google to be redundantly available acrossall the zones within that region.

Meeting your latency, availability, or durability requirements are primaryfactors for selecting the region where your Cloud Run services are run.You can generally select the region nearest to your users but you should considerthe location of theother Google Cloudproducts that are used by your Cloud Run service.Using Google Cloud products together across multiple locations can affectyour service's latency as well as cost.

Cloud Run is available in the following regions:

Subject toTier 1 pricing

  • asia-east1 (Taiwan)
  • asia-northeast1 (Tokyo)
  • asia-northeast2 (Osaka)
  • asia-south1 (Mumbai, India)
  • asia-southeast3 (Bangkok)
  • europe-north1 (Finland)leaf iconLow CO2
  • europe-north2 (Stockholm)leaf iconLow CO2
  • europe-southwest1 (Madrid)leaf iconLow CO2
  • europe-west1 (Belgium)leaf iconLow CO2
  • europe-west4 (Netherlands)leaf iconLow CO2
  • europe-west8 (Milan)
  • europe-west9 (Paris)leaf iconLow CO2
  • me-west1 (Tel Aviv)
  • northamerica-south1 (Mexico)
  • us-central1 (Iowa)leaf iconLow CO2
  • us-east1 (South Carolina)
  • us-east4 (Northern Virginia)
  • us-east5 (Columbus)
  • us-south1 (Dallas)leaf iconLow CO2
  • us-west1 (Oregon)leaf iconLow CO2

Subject toTier 2 pricing

  • africa-south1 (Johannesburg)
  • asia-east2 (Hong Kong)
  • asia-northeast3 (Seoul, South Korea)
  • asia-southeast1 (Singapore)
  • asia-southeast2 (Jakarta)
  • asia-south2 (Delhi, India)
  • australia-southeast1 (Sydney)
  • australia-southeast2 (Melbourne)
  • europe-central2 (Warsaw, Poland)
  • europe-west10 (Berlin)
  • europe-west12 (Turin)
  • europe-west2 (London, UK)leaf iconLow CO2
  • europe-west3 (Frankfurt, Germany)
  • europe-west6 (Zurich, Switzerland)leaf iconLow CO2
  • me-central1 (Doha)
  • me-central2 (Dammam)
  • northamerica-northeast1 (Montreal)leaf iconLow CO2
  • northamerica-northeast2 (Toronto)leaf iconLow CO2
  • southamerica-east1 (Sao Paulo, Brazil)leaf iconLow CO2
  • southamerica-west1 (Santiago, Chile)leaf iconLow CO2
  • us-west2 (Los Angeles)
  • us-west3 (Salt Lake City)
  • us-west4 (Las Vegas)

If you already created a Cloud Run service, you can view theregion in the Cloud Run dashboard in theGoogle Cloud console.

Retrieving the code sample

To retrieve the code sample for use:

  1. Clone the sample app repository to your local machine:

    Node.js

    gitclonehttps://github.com/GoogleCloudPlatform/nodejs-docs-samples.git

    Alternatively, you can download the sample as a zip file and extract it.

    Python

    gitclonehttps://github.com/GoogleCloudPlatform/python-docs-samples.git

    Alternatively, you can download the sample as a zip file and extract it.

    Java

    gitclonehttps://github.com/GoogleCloudPlatform/java-docs-samples.git

    Alternatively, you can download the sample as a zip file and extract it.

  2. Change to the directory that contains the Cloud Run samplecode:

    Node.js

    cdnodejs-docs-samples/run/idp-sql/

    Python

    cdpython-docs-samples/run/idp-sql/

    Java

    cdjava-docs-samples/run/idp-sql/

Visualizing the architecture

Architectural Diagram
Diagram shows an end-user logging-in through a Google sign-in dialog provided by Identity Platform, and then being redirected back to Cloud Run with the user's identity.
  1. An end-user makes the first request to the Cloud Run server.

  2. The client loads in the browser.

  3. The user provides login credentials through the Google sign-in dialogfrom Identity Platform. An alert welcomes the signed-in user.

  4. Control is redirected back to the server. The end-user votes using theclient, which fetches an ID token from Identity Platform and adds it to thevote request header.

  5. When the server receives the request, it verifies the Identity Platform ID token,confirming that the end-user is appropriately authenticated. Then server sendsthe vote to Cloud SQL, using its own credentials.

Understanding the core code

The sample is implemented as client and server, as described next.

Integrating with Identity Platform: client-side code

This sample usesFirebase SDKsto integrate with Identity Platform in order to sign-in and manage users. To connectto Identity Platform, the client-side JavaScript holds the reference to the project'scredentials as a config object and imports the necessaryFirebase JavaScript SDKs:

constconfig={apiKey:'API_KEY',authDomain:'PROJECT_ID.firebaseapp.com',};
<!--FirebaseApp(thecoreFirebaseSDK)isalwaysrequiredandmustbelistedfirst--><scriptsrc="https://www.gstatic.com/firebasejs/7.18/firebase-app.js"></script><!--AddFirebaseAuthservice--><scriptsrc="https://www.gstatic.com/firebasejs/7.18/firebase-auth.js"></script>

The Firebase JavaScript SDK handles the sign-in flow by prompting the end-user tosign-in to their Google Account via a popup window. It then redirects them backto the service.

functionsignIn(){constprovider=newfirebase.auth.GoogleAuthProvider();provider.addScope('https://www.googleapis.com/auth/userinfo.email');firebase.auth().signInWithPopup(provider).then(result=>{// Returns the signed in user along with the provider's credentialconsole.log(`${result.user.displayName} logged in.`);window.alert(`Welcome${result.user.displayName}!`);}).catch(err=>{console.log(`Error during sign in:${err.message}`);window.alert('Sign in failed. Retry or check your browser logs.');});}
Note: To capture browser logging, you may wish to route logs toCloud Logging. For an implementation example, refer toStackdriver Error Reporting library.

When a user successfully signs in, the client uses Firebase methods to mint anID token. The client adds the ID token to theAuthorization header of its requestto the server.

asyncfunctionvote(team){if(firebase.auth().currentUser){// Retrieve JWT to identify the user to the Identity Platform service.// Returns the current token if it has not expired. Otherwise, this will// refresh the token and return a new one.try{consttoken=awaitfirebase.auth().currentUser.getIdToken();constresponse=awaitfetch('/',{method:'POST',headers:{'Content-Type':'application/x-www-form-urlencoded',Authorization:`Bearer${token}`,},body:'team='+team,// send application data (vote)});if(response.ok){consttext=awaitresponse.text();window.alert(text);window.location.reload();}}catch(err){console.log(`Error when submitting vote:${err}`);window.alert('Something went wrong... Please try again!');}}else{window.alert('User not signed in.');}}

Integrating with Identity Platform: server-side code

The server uses theFirebase Admin SDKto verify the user ID token sent from the client. If the providedID token has the correct format, is not expired, and is properly signed, themethod returns the decoded ID token. The server extracts the Identity Platformuidfor that user.

Node.js

constfirebase=require('firebase-admin');// Initialize Firebase Admin SDKfirebase.initializeApp();// Extract and verify Id Token from headerconstauthenticateJWT=(req,res,next)=>{constauthHeader=req.headers.authorization;if(authHeader){consttoken=authHeader.split(' ')[1];// If the provided ID token has the correct format, is not expired, and is// properly signed, the method returns the decoded ID tokenfirebase.auth().verifyIdToken(token).then(decodedToken=>{constuid=decodedToken.uid;req.uid=uid;next();}).catch(err=>{req.logger.error(`Error with authentication:${err}`);returnres.sendStatus(403);});}else{returnres.sendStatus(401);}};

Python

defjwt_authenticated(func:Callable[...,int])->Callable[...,int]:"""Use the Firebase Admin SDK to parse Authorization header to verify the    user ID token.    The server extracts the Identity Platform uid for that user.    """@wraps(func)defdecorated_function(*args:a,**kwargs:a)->a:header=request.headers.get("Authorization",None)ifheader:token=header.split(" ")[1]try:decoded_token=firebase_admin.auth.verify_id_token(token)exceptExceptionase:logger.exception(e)returnResponse(status=403,response=f"Error with authentication:{e}")else:returnResponse(status=401)request.uid=decoded_token["uid"]returnfunc(*args,**kwargs)returndecorated_function

Java

/** Extract and verify Id Token from header */privateStringauthenticateJwt(Map<String,String>headers){StringauthHeader=(headers.get("authorization")!=null)?headers.get("authorization"):headers.get("Authorization");if(authHeader!=null){StringidToken=authHeader.split(" ")[1];// If the provided ID token has the correct format, is not expired, and is// properly signed, the method returns the decoded ID tokentry{FirebaseTokendecodedToken=FirebaseAuth.getInstance().verifyIdToken(idToken);Stringuid=decodedToken.getUid();returnuid;}catch(FirebaseAuthExceptione){logger.error("Error with authentication: "+e.toString());thrownewResponseStatusException(HttpStatus.FORBIDDEN,"",e);}}else{logger.error("Error no authorization header");thrownewResponseStatusException(HttpStatus.UNAUTHORIZED);}}

Connecting the server to Cloud SQL

The server connects to the Cloud SQL instance Unix domain socket usingthe format:/cloudsql/CLOUD_SQL_CONNECTION_NAME.

Node.js

/** * Connect to the Cloud SQL instance through UNIX Sockets * * @param {object} credConfig The Cloud SQL connection configuration from Secret Manager * @returns {object} Knex's PostgreSQL client */constconnectWithUnixSockets=asynccredConfig=>{constdbSocketPath=process.env.DB_SOCKET_PATH||'/cloudsql';// Establish a connection to the databasereturnKnex({client:'pg',connection:{user:credConfig.DB_USER,// e.g. 'my-user'password:credConfig.DB_PASSWORD,// e.g. 'my-user-password'database:credConfig.DB_NAME,// e.g. 'my-database'host:`${dbSocketPath}/${credConfig.CLOUD_SQL_CONNECTION_NAME}`,},...config,});};

Python

definit_unix_connection_engine(db_config:dict[str,int])->sqlalchemy.engine.base.Engine:"""Initializes a Unix socket connection pool for a Cloud SQL instance of PostgreSQL.    Args:        db_config: a dictionary with connection pool config    Returns:        A SQLAlchemy Engine instance.    """creds=credentials.get_cred_config()db_user=creds["DB_USER"]db_pass=creds["DB_PASSWORD"]db_name=creds["DB_NAME"]db_socket_dir=creds.get("DB_SOCKET_DIR","/cloudsql")cloud_sql_connection_name=creds["CLOUD_SQL_CONNECTION_NAME"]pool=sqlalchemy.create_engine(# Equivalent URL:# postgres+pg8000://<db_user>:<db_pass>@/<db_name>#                         ?unix_sock=<socket_path>/<cloud_sql_instance_name>/.s.PGSQL.5432sqlalchemy.engine.url.URL.create(drivername="postgresql+pg8000",username=db_user,# e.g. "my-database-user"password=db_pass,# e.g. "my-database-password"database=db_name,# e.g. "my-database-name"query={"unix_sock":f"{db_socket_dir}/{cloud_sql_connection_name}/.s.PGSQL.5432"# e.g. "/cloudsql", "<PROJECT-NAME>:<INSTANCE-REGION>:<INSTANCE-NAME>"},),**db_config,)pool.dialect.description_encoding=Nonelogger.info("Database engine initialized from unix connection")returnpool

Java

Use theSpring Cloud Google Cloud PostgreSQL starter integration to interact with yourPostgreSQL databases in Cloud SQL using Spring JDBC libraries. Set yourCloud SQL for MySQL config to auto-configure aDataSource bean, which, coupled with Spring JDBC, provides aJdbcTemplate object bean that allows for operations such as querying and modifying a database.

#Uncommentandaddenvvarsforlocaldevelopment#spring.datasource.username=${DB_USER}#spring.datasource.password=${DB_PASSWORD}#spring.cloud.gcp.sql.database-name=${DB_NAME}#spring.cloud.gcp.sql.instance-connection-name=${CLOUD_SQL_CONNECTION_NAME}
privatefinalJdbcTemplatejdbcTemplate;publicVoteController(JdbcTemplatejdbcTemplate){this.jdbcTemplate=jdbcTemplate;}

Handling sensitive configuration with Secret Manager

Secret Manager provides centralized and secure storage of sensitive datasuch as Cloud SQL configuration. The server injects the Cloud SQL credentials fromSecret Manager at runtime via an environment variable. Learn more aboutUsing secrets with Cloud Run.

Node.js

// CLOUD_SQL_CREDENTIALS_SECRET is the resource ID of the secret, passed in by environment variable.// Format: projects/PROJECT_ID/secrets/SECRET_ID/versions/VERSIONconst{CLOUD_SQL_CREDENTIALS_SECRET}=process.env;if(CLOUD_SQL_CREDENTIALS_SECRET){try{// Parse the secret that has been added as a JSON string// to retrieve database credentialsreturnJSON.parse(CLOUD_SQL_CREDENTIALS_SECRET.toString('utf8'));}catch(err){throwError(`Unable to parse secret from Secret Manager. Make sure that the secret is JSON formatted:${err}`);}}

Python

defget_cred_config()->dict[str,str]:"""Retrieve Cloud SQL credentials stored in Secret Manager    or default to environment variables.    Returns:        A dictionary with Cloud SQL credential values    """secret=os.environ.get("CLOUD_SQL_CREDENTIALS_SECRET")ifsecret:returnjson.loads(secret)

Java

/** Retrieve config from Secret Manager */publicstaticHashMap<String,Object>getConfig(){Stringsecret=System.getenv("CLOUD_SQL_CREDENTIALS_SECRET");if(secret==null){thrownewIllegalStateException("\"CLOUD_SQL_CREDENTIALS_SECRET\" is required.");}try{HashMap<String,Object>config=newGson().fromJson(secret,HashMap.class);returnconfig;}catch(JsonSyntaxExceptione){logger.error("Unable to parse secret from Secret Manager. Make sure that it is JSON formatted: "+e);thrownewRuntimeException("Unable to parse secret from Secret Manager. Make sure that it is JSON formatted.");}}

Set up Identity Platform

Identity Platform requires manual setup in the Google Cloud console.

  1. In the Google Cloud console, enable the Identity Platform API:

    Enable the API

  2. Configure your project:

    1. In a new window, go to the Google Auth Platform > Overview page.

      Go to Overview

    2. ClickGet Started and follow the project configuration setup.

    3. In theApp information dialog:

      1. Supply the application name.
      2. Select one of the displayed user support emails.
    4. In theAudience dialog, selectExternal.

    5. In theContact information dialog, enter a contact email.

    6. Agree to the user data policy, then clickCreate.

  3. Create and obtain your OAuth Client ID and Secret:

    1. In the Google Cloud console, go to the APIs & Services > Credentials page.

      Go to Credentials

    2. At the top of the page, clickCreate Credentials and selectOAuth client ID.

    3. FromApplication Type, selectWeb Application and supply the name.

    4. ClickCreate

    5. Theclient_id andclient_secret values will be used in the next step.

  4. Configure Google as a provider:

    1. In the Google Cloud console, go to the Identity Providers page.

      Go to Identity Providers

    2. ClickAdd A Provider.

    3. SelectGoogle from the list.

    4. In the Web SDK Configuration settings, enter theclient_id andclient_secret values from theprevious step.

    5. UnderConfigure your application, clickSetup Details.

  5. Copy the configuration to your application:

    • Copy theapiKey andauthDomain values into the sample'sstatic/config.js to initialize the Identity Platform Client SDK.
Note: This configuration is not yet complete. After you deploy your Cloud Run server,you still need to authorize your service domain, as described inFinishing touches.

Deploying the service

Follow the steps to complete infrastructure provisioning and deployment:

  1. Create a Cloud SQL instance with postgreSQL database using theconsole or CLI:

    gcloudsqlinstancescreateCLOUD_SQL_INSTANCE_NAME\--database-version=POSTGRES_16\--region=CLOUD_SQL_REGION\--cpu=2\--memory=7680MB\--root-password=DB_PASSWORD
  2. Add your Cloud SQL credential values topostgres-secrets.json:

    Node.js

    {"CLOUD_SQL_CONNECTION_NAME":"PROJECT_ID:REGION:INSTANCE","DB_NAME":"postgres","DB_USER":"postgres","DB_PASSWORD":"PASSWORD_SECRET"}

    Python

    {"CLOUD_SQL_CONNECTION_NAME":"PROJECT_ID:REGION:INSTANCE","DB_NAME":"postgres","DB_USER":"postgres","DB_PASSWORD":"PASSWORD_SECRET"}

    Java

    {"spring.cloud.gcp.sql.instance-connection-name":"PROJECT_ID:REGION:INSTANCE","spring.cloud.gcp.sql.database-name":"postgres","spring.datasource.username":"postgres","spring.datasource.password":"PASSWORD_SECRET"}

  3. Create a versioned secret using theconsole or CLI:

    gcloudsecretscreateidp-sql-secrets\--replication-policy="automatic"\--data-file=postgres-secrets.json
  4. Create a service account for the server using theconsole or CLI:

    gcloudiamservice-accountscreateidp-sql-identity
  5. Grant roles for Secret Manager and Cloud SQL access using theconsole or CLI:

    1. Allow the service account associated with the server to access the created secret:

      gcloudsecretsadd-iam-policy-bindingidp-sql-secrets\--memberserviceAccount:idp-sql-identity@PROJECT_ID.iam.gserviceaccount.com\--roleroles/secretmanager.secretAccessor
    2. Allow the service account associated with the server to access Cloud SQL:

      gcloudprojectsadd-iam-policy-bindingPROJECT_ID\--memberserviceAccount:idp-sql-identity@PROJECT_ID.iam.gserviceaccount.com\--roleroles/cloudsql.client
  6. Create an Artifact Registry:

    gcloudartifactsrepositoriescreateREPOSITORY\--repository-formatdocker\--locationREGION
    • REPOSITORY is the name of the repository. For each repository location in a project, repository names must be unique.
  7. Build the container image using Cloud Build:

    Node.js

    gcloudbuildssubmit--tagREGION-docker.pkg.dev/PROJECT_ID/REPOSITORY/idp-sql

    Python

    gcloudbuildssubmit--tagREGION-docker.pkg.dev/PROJECT_ID/REPOSITORY/idp-sql

    Java

    This sample usesJib to buildDocker images using common Java tools. Jib optimizes container builds withoutthe need for a Dockerfile or havingDockerinstalled. Learn more aboutbuilding Java containers with Jib.

    1. Use thegcloud credential helperto authorize Docker to push to your Artifact Registry.

      gcloudauthconfigure-docker

    2. Use the Jib Maven Plugin to build and push the container to Artifact Registry.

      mvncompilejib:build-Dimage=REGION-docker.pkg.dev/PROJECT_ID/REPOSITORY/idp-sql

  8. Deploy the container image to Cloud Run using theconsoleor CLI. Note that the server is deployed to allow unauthenticated access.This is so that the user can load the client and begin the process. Theserver verifies the ID token added to the vote request manually,authenticating the end-user.

    gcloudrundeployidp-sql\--imageREGION-docker.pkg.dev/PROJECT_ID/REPOSITORY/idp-sql\--allow-unauthenticated\--service-accountidp-sql-identity@PROJECT_ID.iam.gserviceaccount.com\--add-cloudsql-instancesPROJECT_ID:REGION:CLOUD_SQL_INSTANCE_NAME\--update-secretsCLOUD_SQL_CREDENTIALS_SECRET=idp-sql-secrets:latest

    Also note the flags,--service-account,--add-cloudsql-instances, and--update-secrets, which specify the service identity, the Cloud SQLinstance connection, and the secret name with version as an environmentvariable, respectively.

    Note: Environment variables are resolved at instance startup time, so if you use this method, Google recommends that you pin the secret to a particular version rather than usinglatest.

Finishing touches

Identity Platform requires that you authorize the Cloud Run service URLas an allowed redirect after it has signed in the user:

  1. Edit the Google provider by clicking the pen icon in theIdentityProviders page.

  2. ClickAdd Domain under Authorized Domains on the right panel, and enterthe Cloud Run service URL.

    You can locate the service URL in the logs after the build or deployment oryou can find it anytime using:

    gcloudrunservicesdescribeidp-sql--format'value(status.url)'
  3. Go to the APIs & Services > Credentials page

    1. Click the pencil icon beside your OAuth Client ID to edit it and under theAuthorized redirect URIs click theAdd URI button.

    2. In the field copy and paste the following URL and click theSave button at the bottom of the page.

    https://PROJECT_ID.firebaseapp.com/__/auth/handler

Trying it out

To try out the complete service:

  1. Navigate your browser to the URL provided by the deployment step above.

  2. Click theSign in with Google button and go through the authentication flow.

  3. Add your vote!

    It should look like this:

    User Interface shows vote count for each team and a list of votes.

    Success: You deployed a Cloud Run service that authenticates end-users with Identity Platform and securely manages sensitive data using Secret Manager.

If you choose to continue developing these services, remember that they haverestricted Identity and Access Management (IAM) access to the rest of Google Cloud andwill need to be given additional IAM roles to access many otherservices.

Clean up

To avoid additional charges to your Google Cloud account, delete all the resourcesyou deployed with this tutorial.

Delete the project

If you created a new project for this tutorial, delete the project.If you used an existing project and need to keep it without the changes you addedin this tutorial,delete resources that you created for the tutorial.

The easiest way to eliminate billing is to delete the project that you created for the tutorial.

To delete the project:

    Caution: Deleting a project has the following effects:
    • Everything in the project is deleted. If you used an existing project for the tasks in this document, when you delete it, you also delete any other work you've done in the project.
    • Custom project IDs are lost. When you created this project, you might have created a custom project ID that you want to use in the future. To preserve the URLs that use the project ID, such as anappspot.com URL, delete selected resources inside the project instead of deleting the whole project.

    If you plan to explore multiple architectures, tutorials, or quickstarts, reusing projects can help you avoid exceeding project quota limits.

  1. In the Google Cloud console, go to theManage resources page.

    Go to Manage resources

  2. In the project list, select the project that you want to delete, and then clickDelete.
  3. In the dialog, type the project ID, and then clickShut down to delete the project.

Delete tutorial resources

  1. Delete the Cloud Run service you deployed in this tutorial.Cloud Run services don't incur costs until they receive requests.

    To delete your Cloud Run service, run the following command:

    gcloudrunservicesdeleteSERVICE-NAME

    ReplaceSERVICE-NAME with the name of your service.

    You can also delete Cloud Run services from theGoogle Cloud console.

  2. Remove thegcloud default region configuration you added during tutorialsetup:

    gcloudconfigunsetrun/region
  3. Remove the project configuration:

     gcloud config unset project
  4. Delete other Google Cloud resources created in this tutorial:

What's next

Except as otherwise noted, the content of this page is licensed under theCreative Commons Attribution 4.0 License, and code samples are licensed under theApache 2.0 License. For details, see theGoogle Developers Site Policies. Java is a registered trademark of Oracle and/or its affiliates.

Last updated 2026-02-19 UTC.