
Streamlit enables developers to build full-fledged web applications in Python and is widely adopted for internal AI tools and data apps. To run a Streamlit app in production, however, you need to add user authentication. This article compares the main ways to implement authentication in a Streamlit app, assuming an internal-facing use case.
Open ID Connect (OIDC)
Open ID Connect (OIDC) is the authentication method officially supported by Streamlit. It relies on the open OIDC protocol used by many identity providers (IdPs). OIDC is available from Streamlit v1.32 onward.
To use OIDC, you must connect your app to an external IdP that performs the actual login. The docs showcase Auth0 and Google Identity, but any OIDC-compliant IdP will work.
The upside is that you can reuse an IdP your company already operates. The downside is that you must have one—if none exists, you’ll have to choose and set up a new IdP.
How to implement OIDC
Streamlit app code
import streamlit as st
if not st.experimental_user.is_logged_in:
st.login("oidc")
st.stop()
user = st.experimental_user
st.sidebar.markdown(f"**👋 Hello {user.email}!**")
st.button("Logout", on_click=st.logout)
Supplying IdP settings via environment variables
The official docs suggest putting IdP settings in .streamlit/secrets.toml
, but that only works smoothly on Streamlit Community Cloud and requires a complex deployment workflow for your own cloud. A more portable approach is to read them from environment variables.
Example for Auth0:
.env
REDIRECT_URI=http://localhost:8501/oauth2callback
COOKIE_SECRET=<random string>
CLIENT_ID=<Auth0 client ID>
CLIENT_SECRET=<Auth0 client secret>
AUTH0_METADATA_URL=https://<tenant>.auth0.com/.well-known/openid-configuration
app.py
import streamlit as st
import os
from dotenv import load_dotenv
def load_auth_config():
load_dotenv() # Load variables from .env
from streamlit.runtime.secrets import secrets_singleton
auth_secrets = {
"auth": {
"redirect_uri": os.getenv("REDIRECT_URI"),
"cookie_secret": os.getenv("COOKIE_SECRET"),
"auth0": {
"client_id": os.getenv("CLIENT_ID"),
"client_secret": os.getenv("CLIENT_SECRET"),
"server_metadata_url": os.getenv("AUTH0_METADATA_URL"),
"client_kwargs": { "prompt": "login" }
}
}
}
# Inject settings into Streamlit’s secret store
secrets_singleton._secrets = auth_secrets
for k, v in auth_secrets.items():
secrets_singleton._maybe_set_environment_variable(k, v)
load_auth_config()
if not st.experimental_user.is_logged_in:
st.login("oidc")
st.stop()
user = st.experimental_user
st.sidebar.markdown(f"**👋 Hello {user.email}!**")
st.button("Logout", on_click=st.logout)
Drawbacks
- You must provision an IdP. If your company already has one for internal apps, great. Otherwise, you’ll need to build or buy one.
- Capabilities depend on the IdP. Whether you can attach custom metadata (roles, departments, etc.), use SSO, or support SAML is determined by the IdP’s feature set.
Example: With Auth0 you can define global user roles, but you have to call Auth0’s API to retrieve them. - Multiple apps = multiple IdP configurations. Even with role support, managing per-app restrictions often means creating separate applications or user pools in the IdP—adding operational cost.
Streamlit Authenticator
Streamlit Authenticator is a popular community package that lets you add authentication without an external IdP.
Credentials and user metadata are defined in a YAML file, which can include roles for simple access control.
How to implement
config.yaml
cookie:
expiry_days: 30
key: <any string>
name: <any string>
credentials:
usernames:
jsmith:
email: jsmith@gmail.com
password: abc # Will be hashed automatically
roles: # Optional
- admin
- editor
- viewer
app.py
import streamlit as st
import streamlit_authenticator as stauth
import os
from dotenv import load_dotenv
from yaml import safe_load
with open("config.yaml") as f:
config = safe_load(f)
load_dotenv()
authenticator = stauth.Authenticate(
credentials = config["credentials"],
cookie_name = "my_app",
cookie_key = os.getenv("COOKIE_SECRET_KEY"),
cookie_expiry_days = 7,
)
name, auth_status, _ = authenticator.login("Login", "main")
if auth_status is False:
st.error("Incorrect username or password")
elif auth_status is None:
st.warning("Please enter your username and password")
else:
st.sidebar.success(f"Welcome {name}")
# Business logic here
if st.sidebar.button("Logout"):
authenticator.logout("Logout", "sidebar")
Drawbacks
- No SSO/SAML support. Social logins (Google, GitHub, …) and enterprise SAML are not available.
- Production needs extra work. You still have to build flows for password reset, forgotten usernames, profile updates, etc.
- Every config change = redeploy. Because users live in YAML, any update requires editing the file and redeploying. Managing large user bases in YAML quickly becomes painful.
Squadbase
Squadbase is a delivery platform with built-in authentication for internal apps. It supports Streamlit as well as frameworks such as Next.js and Ollama.
Key features
Built-in user authentication
Only team members invited via the Squadbase dashboard can access a deployed app—zero code required. Squadbase authentication supports SSO out of the box.
Once you connect a GitHub repository, continuous deployment and a secure runtime are set up automatically. Think of Vercel or Netlify, but purpose-built for internal apps.
Role management
Squadbase lets you assign:
- Team roles – control who can deploy or manage the platform.
- Project roles – per-app permissions. Your application code can read the current user’s role via the SDK.
# (Example role definition would go here)
Because roles are defined per project, you can manage permissions for multiple apps from a single platform.
Log monitoring & user analytics
Runtime logs and access logs are collected automatically. Aggregated analytics are visible in a dashboard, helping teams operate and improve their internal tools.
(Analytics screenshot)
(CTA)
Final Thoughts
Finally, let's consider selection by use case or situation.
Need to keep using an existing IdP and no role management
If your company already runs an IdP and you simply need to reuse it, Streamlit OIDC is the fastest path. Just plug in the existing settings.
Be aware, though, that managing roles or multiple apps through the IdP can become labor-intensive.
Need new authentication and role-based access control
We (unsurprisingly) recommend Squadbase 😊. It adds authentication without touching your Streamlit code, and the SDK makes role-driven business logic easy.
Plus you get log collection, monitoring, and user analytics for free.
Just need “good-enough” auth and aren’t ready for full production
Streamlit Authenticator may suffice: no IdP required, everything lives in your codebase.
But if you foresee growth, remember you’ll need to implement additional user-management flows and maintain a large YAML file—challenges that often push teams toward a platform like Squadbase anyway.