close
Sitemap
Google Cloud - Community

A collection of technical articles and blogs published or curated by Google Cloud Developer Advocates. The views expressed are those of the authors and don't necessarily reflect those of Google.

Adding Authentication and Authorisation to our Rickbot Streamlit Chatbot with OAuth and the Google Auth Platform

9 min readJun 26, 2025

--

Press enter or click to view image in full size
Image

Context

This article follows the the article Creating a Rick & Morty Chatbot with Google Cloud and the Gen AI SDK.

We may want to add authentication and authorisation to our Rickbot application. Authentication is the process of validating that a user is who they say they are, and authorisation is the process of checking what the user is allowed to do.

In the old days you would have to write your own authentication and authorisation code in your application, and maintain your own database of users. But the modern industry-standard is to use OAuth 2.0 for authorisation, combined with OIDC (Open ID Connect) for authentication. This framework allows our application to leverage another trusted platform (like Google or GitHub) for both authentication and authorisation.

Here, we will use Google Auth Platform to authenticate any user that wants to use the Rickbot. For demo purposes, my only requirement is that a user has a valid gmail identity.

The Rickbot Series

Just for orientation, this is where you are in the series:

  1. Creating a Rick & Morty Chatbot with Google Cloud and the Gen AI SDK
  2. Adding Authentication and Authorisation to our Rickbot Streamlit Chatbot with OAuth and the Google Auth Platform — you are here
  3. Building the Rickbot Multi-Personality Agentic Application using Gemini CLI, Google Agent-Starter-Pack and the Agent Development Kit (ADK)
  4. Updating the Rickbot Multi-Personality Agentic Application — Integrate Agent Development Kit (ADK) using Gemini CLI
  5. Guided Implementation of Agent Development Kit (ADK) with the Rickbot Multi-Personality Application (Series)
  6. Productionising the Rickbot ADK Application and More Gemini CLI Tips
  7. Get Schwifty with the FastAPI: Adding a FastAPI to our Agentic Application
  8. Introducing ADK Artifacts for Multi-Modal File Handling (a Rickbot Blog)
  9. Using Gemini File Search Tool for RAG (a Rickbot Blog)

Overview of Steps

This is the approach we’ll take:

  1. We will configure OAuth in the Google Auth Platform, on Google Cloud.
  2. Add OAuth to our Streamlit application, providing login and logout capability, using the Google Auth Platform.
  3. Add an AUTH_REQUIRED variable, so we can easily turn authentication on or off.
  4. Test the authentication using local configuration.
  5. Securely store the OAuth credentials in Google Secret Manager.
  6. Inject these OAuth credentials into our Rickbot container in Cloud Run.

Let’s get cracking!

Configure OAuth in the Google Auth Platform

This is where we tell the Google Cloud Auth Platform about the Rickbot application. We will obtain unique OAuth credentials that the application will use to identify itself to Google.

From the Google Console, navigate to the Auth Platform.

Press enter or click to view image in full size
Image
Google Auth Platform

Go to Branding:

Press enter or click to view image in full size
Image
App branding

Note: if you choose to publish your application to production and want to allow authentication by users outside of your domain, then Google will enforce certain requirements. For example, you will need a dedicated URL for your privacy policy.

For authorised domains, you’ll want to include your Cloud Run service domain (e.g. myservice.europe-west4.run.app) and any top level domain for if you use a DNS alias for your service, e.g. myservice.mydomain.com.

Set the Audience:

Press enter or click to view image in full size
Image
Specify audience

We’ll set to External and whilst the app is in testing mode, we’ll need to add one or more test users.

Now we set up the client. Click Create client.

Press enter or click to view image in full size
Image
Client setup

Set the application type to “Web application”, and specify an internal name used by the client.

Now we need to supply the OAuth redirect URL. We’ll initially want to test it locally, so we can use the localhost URL and add “oauth2callback”. I can also provide the URL of the application when running in Google Cloud Run. (Make sure this URL starts with https and not http.)

Press enter or click to view image in full size
Image
Get your redirect URL
Press enter or click to view image in full size
Image
OAuth Redirect URIs

After clicking create, the OAuth client will be created:

Press enter or click to view image in full size
Image
OAuth client information

The provided client information needs to be supplied by our Rickbot application. Make sure you copy this information straight away; you can’t retrieve it later!

You can view your clients here:

Press enter or click to view image in full size
Image
OAuth clients

Configure the Streamlit Application to Use OAuth

Install Python Authlib Package

Streamlit OAuth integration makes use of the Python Authlib package. So update your requirements.txt:

streamlit==1.45.1
google-genai==1.20.0
Authlib==1.6.0

Then install the package locally, e.g. using pip or uv.

Configuring the Streamlit App Locally

For local testing, we will copy the OAuth client credentials into .streamlit/secrets.toml. Make sure this file is included in your .gitignore so that you don’t accidentally check-in any credentials to GitHub! Publishing your client secrets to GitHub is… not ideal.

[auth]
redirect_uri = "http://localhost:8501/oauth2callback"
cookie_secret = "some_random_secret"
client_id = "xxx"
client_secret = "xxx"
server_metadata_url = "https://accounts.google.com/.well-known/openid-configuration"

The client_id and client_secret values are the ones you created in Google Cloud earlier. The cookie_secret can be any value you like.

Let’s add an option to configure whether authentication is required in our application or not. This will allow us to turn this feature on or off at will. Back in app.py, add this extra line to our Config class:

@dataclass
class Config:
"""Holds application configuration."""
project_id: str
region: str
logger: logging.Logger
auth_required: bool # Whether we require logon

And in our get_config() function, we’ll add this line to retrieve the auth setting from an environment variable. It defaults to True.

    auth_required = os.environ.get("AUTH_REQUIRED", "True").lower() == "true"

Now all we need to do is add some login and logout code to our app.py:

### Previous code

# --- Title and Introduction ---
st.title(f"Wubba Lubba Dub Dub! I'm {APP_NAME}.")

def show_page():
st.caption("Ask me something. Or don't. Whatever.")

# --- Session State Initialization ---
# For maintaining the conversation history.
if "messages" not in st.session_state:
st.session_state.messages = []

# --- Sidebar for Configuration ---
with st.sidebar:
# Add logout button
if config.auth_required and st.user.is_logged_in:
st.caption(f"Welcome, {st.user.name}")
st.button("Log out", on_click=st.logout)

# Remaining code from before, starting with...
st.info("I'm Rick Sanchez. The smartest man in the universe. I may be cynical and sarcastic. User discretion is advised.")
# The rest...

# Login with Google OAuth
if config.auth_required:
if not st.user.is_logged_in:
_, mid, _ = st.columns([0.2, 0.6, 0.2])
with mid:
st.markdown(":sunglasses: Please login to use Rickbot. Any Google account will do.")
if st.button("Log in with Google", use_container_width=True):
st.login()
else:
show_page()
else:
show_page()

I’ve wrapped the original page generation code in a function called that show_page(). This function is only executed when a user is successfully authenticated. And because the sidebar is now part of the show_page() function, the sidebar only appears when a user is authenticated. So we can safely put our Logout button at the top of the sidebar.

Test It Locally

uv run -- streamlit run app.py --browser.serverAddress=localhost

When we launch the application, it now looks like this:

Press enter or click to view image in full size
Image
Rickbot — not authenticated

If we click on Log in, we’re redirected to Google authentication:

Press enter or click to view image in full size
Image
Authenticate with Google

And once logged in, we can use the Rickbot as before:

Press enter or click to view image in full size
Image
Logged in to Rickbot

Configuring in Google Cloud

When we deploy our application to Cloud Run in Google Cloud, we need to securely store our OAuth credentials. We can’t simply include the secrets.toml in our source code! Since we’re already using Google Cloud, probably the best way to do this is to store the credentials in Google Secret Manager.

At first I thought I could just define the secrets and reference them as variables in the Streamlit application. But it turns out that the Streamlit OAuth capability (e.g. the st.login() function) actually requires that the auth secrets are defined in the .streamlit/secrets.toml. (I viewed the Streamlit source code to verify this.)

So what I’ll do is store the contents of secrets.toml in Google Secret Manager, and then write a simple Python helper file that will use this to dynamically create a local .streamlit/secrets.toml when the application starts up.

Secret Manager

First, we create a secret in Secret Manager with our secrets.toml.

Open Secret Manager in the Google Cloud Console:

Press enter or click to view image in full size
Image
Secret Manager

Create a new secret, and copy/paste the contents of secrets.toml. It will contain the same details as our local file, but uses the Cloud Run URL, rather than localhost.

[auth]
redirect_uri = "https://your-actual-Cloud-Run-URL/oauth2callback"
cookie_secret = "the_random_secret"
client_id = "xxx"
client_secret = "xxx"
server_metadata_url = "https://accounts.google.com/.well-known/openid-configuration"

I’m calling the secret rickbot-streamlit-secrets-toml:

Press enter or click to view image in full size
Image
Add a secret

Done:

Press enter or click to view image in full size
Image
Secret created

Allow Your Service Account to Access Your Secrets

Recall that our Rickbot application runs under a service account. We need to give this service account permission to access the secret we’ve created:

# To provide access to Google Secret Manager
gcloud projects add-iam-policy-binding $GOOGLE_CLOUD_PROJECT \
--member="serviceAccount:$RICKBOT_SA_EMAIL" \
--role="roles/secretmanager.secretAccessor"

Creating the Python Script

We’re going to need to use the Google client library google-cloud-secret-manager to programmatically retrieve secrets from Secret Manager. So add this package to your requirements.txt and then refresh your packages.

Now let’s make a new file in the same folder as the Rickbot app.py, called create_auth_secrets.py:

""" Creates local .streamlit/secrets.toml from secret in Google Secret Manager 
We can run this from our app code or standalone. """
import os
from functools import lru_cache
from google.cloud import secretmanager

@lru_cache
def create_secrets_toml(google_project_id: str):
streamlit_dir = ".streamlit"
secrets_file_path = os.path.join(streamlit_dir, "secrets.toml")

if os.path.exists(secrets_file_path):
print(".streamlit/secrets.toml already exists, skipping creation.")
return # Nothing to do

print("Retrieving OAuth credentials.")
secret_name = os.environ.get("STREAMLIT_SECRETS_SECRET_NAME", "rickbot-streamlit-secrets-toml")
secret_version = os.environ.get("STREAMLIT_SECRETS_SECRET_VERSION", "latest")

client = secretmanager.SecretManagerServiceClient()
name = f"projects/{google_project_id}/secrets/{secret_name}/versions/{secret_version}"

try:
response = client.access_secret_version(request={"name": name})
secrets_content = response.payload.data.decode("UTF-8")

os.makedirs(streamlit_dir, exist_ok=True)
print(".streamlit/ created.")
with open(secrets_file_path, "w") as f:
f.write(secrets_content)
print(f"Successfully created {secrets_file_path}")

except Exception as e:
raise ValueError(f"Error accessing secret '{secret_name}' from Secret Manager: {e}") from e

if __name__ == "__main__":
project_id = os.environ.get("GOOGLE_CLOUD_PROJECT")
create_secrets_toml(project_id)

Let’s try it out:

python3 create_auth_secrets.py

And the output:

Press enter or click to view image in full size
Image
Script output

That was easy!

We can run this script from within our application code:

# Login with Google OAuth
if config.auth_required:
# If we want to create the secrets.toml in the app code...
try:
create_secrets_toml(config.project_id)
except ValueError as e:
logger.error(f"Failed to setup auth: {e}", exc_info=True)
st.error(f"⚠️ Could not initialize the application. Please check your configuration. Error: {e}")
st.stop()

if not st.user.is_logged_in:
# As before...

And whilst we’re here, it’s important that any development .streamlit/secrets.toml doesn’t get included in our container image. So let’s create a .dockerignore file (in the root of our application folder again) to exclude it:

# Ignore dev secrets
.streamlit/secrets.toml

# Ignore Docker-related files
Dockerfile*
.dockerignore

Deploying to Google Cloud Run

So that’s it! If we now push our code changes back into the main branch of our GitHub repo, our CI/CD will automatically deploy the new version to Cloud Run.

And because I’ve made _AUTH_REQUIRED a substitution variable in my Cloud Build trigger, I can deploy with or without authentication just by changing this value.

Press enter or click to view image in full size
Image
Deploying with or without authentication

Wrap-Up

We’ve added OAuth to our Rickbot, requiring that users are authenticated and authorised to use the app. We’re using the Google Auth Platform to do the authentication and authorisation for us.

We’ve added configuration to the Rickbot deployment, in order to enable or disable the authentication requirement.

Hope you enjoyed!

Before You Go

  • Please share this with anyone that you think will be interested. It might help them, and it really helps me!
  • Please give me 50 claps! (Just hold down the clap button.)
  • Feel free to leave a comment 💬.
  • Follow and subscribe, so you don’t miss my content. Go to my Profile Page, and click on these icons:
Image
Follow and Subscribe

Links

--

--

Google Cloud - Community
Google Cloud - Community

Published in Google Cloud - Community

A collection of technical articles and blogs published or curated by Google Cloud Developer Advocates. The views expressed are those of the authors and don't necessarily reflect those of Google.

Dazbo (Darren Lester)
Dazbo (Darren Lester)

Written by Dazbo (Darren Lester)

Cloud Architect and moderate geek. Google Cloud evangelist. I love learning new things, but my brain is tiny. So when something goes in, something falls out!

No responses yet