Adding Authentication and Authorisation to our Rickbot Streamlit Chatbot with OAuth and the Google Auth Platform
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:
- Creating a Rick & Morty Chatbot with Google Cloud and the Gen AI SDK
- Adding Authentication and Authorisation to our Rickbot Streamlit Chatbot with OAuth and the Google Auth Platform — you are here
- Building the Rickbot Multi-Personality Agentic Application using Gemini CLI, Google Agent-Starter-Pack and the Agent Development Kit (ADK)
- Updating the Rickbot Multi-Personality Agentic Application — Integrate Agent Development Kit (ADK) using Gemini CLI
- Guided Implementation of Agent Development Kit (ADK) with the Rickbot Multi-Personality Application (Series)
- Productionising the Rickbot ADK Application and More Gemini CLI Tips
- Get Schwifty with the FastAPI: Adding a FastAPI to our Agentic Application
- Introducing ADK Artifacts for Multi-Modal File Handling (a Rickbot Blog)
- Using Gemini File Search Tool for RAG (a Rickbot Blog)
Overview of Steps
This is the approach we’ll take:
- We will configure OAuth in the Google Auth Platform, on Google Cloud.
- Add OAuth to our Streamlit application, providing
loginandlogoutcapability, using the Google Auth Platform. - Add an
AUTH_REQUIREDvariable, so we can easily turn authentication on or off. - Test the authentication using local configuration.
- Securely store the OAuth credentials in Google Secret Manager.
- 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.
Go to 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:
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.
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.)
After clicking create, the OAuth client will be created:
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:
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.0Then 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 logonAnd 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=localhostWhen we launch the application, it now looks like this:
If we click on Log in, we’re redirected to Google authentication:
And once logged in, we can use the Rickbot as before:
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:
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:
Done:
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.pyAnd the 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*
.dockerignoreDeploying 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.
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:
Links
- The Rickbot
- Rickbot on GitHub
- Creating a Rick & Morty Chatbot with Google Cloud and the Gen AI SDK
- Streamlit Authentication with Google Auth Platform
- Streamlit: st.login()
- Streamlit source code on GitHub
- Authlib: Python authentication

