As of February 2024, Streamlit 1.42 has been released with a new authentication mechanism to control access to your app. Your users will now be able to authenticate themselves using various authentication providers like Google, Microsoft, GitHub, or with email & password through Okta, as well as all other OpenID providers.

Let’s take a look at how to set up these authentication methods and determine if they fit your application and workflow.

Setup

First, we’ll need to install the required libraries. To have the authentication feature working, Authlib must be installed:

pip install streamlit authlib

Let’s start by using Auth0 to see how we can set up the login functionality:

import streamlit as st

st.title("Protected App Demo")

if not st.experimental_user.get("is_logged_in", False):
    if st.button("Login"):
        st.login("auth0")
else:
    if st.button("Log out"):
        st.logout()
    st.write(f"Hello, {st.experimental_user.name}!")

To configure login functionality, you can use either the .streamlit/secrets.toml file (specific to Streamlit.io Cloud platform) or environment variables. While .streamlit/secrets.toml works well locally and on Streamlit.io Cloud, it’s not supported across all platforms. Additionally, storing secrets directly in this file and uploading it poses security risks. Instead, we recommend using environment variables with Streamlit’s built-in st.secrets functionality, which provides better security and broader platform compatibility.

secrets.toml

[auth]
redirect_uri = "http://localhost:8501/oauth2callback"
cookie_secret = "RANDOM SECRET STRING"

[auth.auth0]
client_id = "CLIENT_ID_XXX"
client_secret = "CLIENT_SECRET_XXX"
server_metadata_url = "https://{AUTH0_DOMAIN}/.well-known/openid-configuration"
client_kwargs = { "prompt" = "login" }

While using secrets.toml is convenient for initial development, it doesn’t allow for easy deployment of your application. A more flexible approach is to use environment variables, which can be configured easily on any deployment platform.

Environment Variables

While Streamlit’s documentation primarily focuses on using .streamlit/secrets.toml, this secrets file isn’t supported on the majority of Cloud Platforms which can be used to deploy your app. A more versatile way to provide the necessary variables to the st.login() function that works across any platform is by providing the values as environment variables and subsequently loading those values into the st.secrets dictionary used by st.login. By examining the Streamlit source code (as this method isn’t explicitly documented), we can implement the following solution that works with secure secrets management on all major platforms:

Let’s declare our secrets in a .env file:

REDIRECT_URI=http://localhost:8501/oauth2callback
COOKIE_SECRET=...
CLIENT_ID=...
CLIENT_SECRET=...
AUTH0_DOMAIN=https://{account}.{region}.auth0.com/.well-known/openid-configuration

In your application, create a function that loads the environment variables and adds them to st.secrets, which is used by st.login:

import streamlit as st
import os
from dotenv import load_dotenv

st.title("Protected App")

def load_auth_config():
    """ 
    Load environment variables into st.secrets 
    - Done through the underlying secret._secrets singleton
      as the secrets.key = value is read-only
    """
    load_dotenv()
    # Access the singleton directly
    from streamlit.runtime.secrets import secrets_singleton
    
    # Define your secrets based on your desired OpenID provider
    # You'll need to convert the `toml` config to a dict
    # - https://docs.streamlit.io/develop/api-reference/user/st.login
    auth_secrets = {
        "auth": {
            "redirect_uri": f"{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_DOMAIN'),
                "client_kwargs": {
                    "prompt": "login"
                }
            }
        }
    }
    
    # Update the singleton's secrets
    secrets_singleton._secrets = auth_secrets
    
    # Update environment variables
    for k, v in auth_secrets.items():
        secrets_singleton._maybe_set_environment_variable(k, v)

# Load the config
load_auth_config()

With this setup, we can use Streamlit’s login system without depending on the .streamlit/secrets.toml file, giving us more flexibility in where we deploy our application.

Logging In

Now that we have everything configured, we have a working authentication mechanism that can use any OpenID provider:

load_auth_config()

if not st.experimental_user.get("is_logged_in", False):
    st.header("Log in:")
    if st.button("Auth0"):
        st.login("auth0")
else:
    if st.button("Log out"):
        st.logout()
    st.write(f"Hello, {st.experimental_user.name}!")

Streamlit with Authentication

Working with User Information

After successful authentication, Streamlit provides access to user information through the st.experimental_user object.

Note on Experimental Interface

While the Streamlit documentation for st.experimental_user show us how to use it, my current testing shows that a more robust approach is needed to avoid potential errors with the changing API. (Thus the experimental par of the experimental_user). For example, when checking login status, I needed to use:

if not st.experimental_user.get("is_logged_in", False):
    # Handle non-authenticated state

Otherwise, an error was thrown in the case the user wasn’t connected.

Available User Information by Provider

Different authentication providers expose different user information. Here’s what you can expect from major providers:

Google Authentication

When using Google as your authentication provider, st.experimental_user provides these attributes:

{
    # Authentication Status
    "is_logged_in": true,
    
    # Provider Information
    "iss": "https://accounts.google.com",
    "azp": "{client_id}.apps.googleusercontent.com",
    "aud": "{client_id}.apps.googleusercontent.com",
    
    # User Identification
    "sub": "{unique_user_id}",
    "email": "{user}@gmail.com",
    "email_verified": true,
    
    # User Profile
    "name": "{full_name}",
    "given_name": "{given_name}",
    "family_name": "{family_name}",
    "picture": "https://lh3.googleusercontent.com/a/{content_path}",
    
    # Security and Session
    "at_hash": "{access_token_hash}",
    "nonce": "{nonce_string}",
    "iat": {issued_time},
    "exp": {expiration_time}
}

Microsoft Entra ID

With Microsoft Entra ID authentication, you’ll have access to:

{
    # Authentication Status
    "is_logged_in": true,
    "ver": "2.0",
    
    # Provider Information
    "iss": "https://login.microsoftonline.com/{tenant_id}/v2.0",
    "aud": "{application_id}",
    "tid": "{tenant_id}",
    
    # User Identification
    "sub": "{application_user_id}",
    "oid": "{user_GUID}",
    "email": "{email}",
    
    # User Profile
    "name": "{full_name}",
    "preferred_username": "{username}",
    
    # Security and Session
    "exp": {expiration_time},
    "iat": {issued_time},
    "nbf": {start_time},
    "nonce": "{nonce_string}",
    "aio": "{opaque_string}"
}

Supported Providers

Streamlit’s authentication system supports any OpenID Connect (OIDC) provider. Here are some popular providers you can integrate with:

For each provider, you can see the required environment variables and the corresponding Python code to load them into st.secrets by clicking on the triangle:

Google Authentication

Use this when you want to let people sign in with their Google accounts. Most people have one, making it a convenient choice for general-purpose apps.

  • Read the Google Identity OpenID Connect documentation - Here
Click to view setup

First, create a .env file with the following variables:

REDIRECT_URI=http://localhost:8501/oauth2callback
COOKIE_SECRET=your_secure_cookie_secret
GOOGLE_CLIENT_ID=your_google_client_id
GOOGLE_CLIENT_SECRET=your_google_client_secret

Then use this Python code to configure Google authentication:

import streamlit as st
import os
from dotenv import load_dotenv
from streamlit.runtime.secrets import secrets_singleton

def load_google_config():
    """Load Google authentication configuration"""
    load_dotenv()
    
    auth_secrets = {
        "auth": {
            "redirect_uri": os.getenv('REDIRECT_URI'),
            "cookie_secret": os.getenv('COOKIE_SECRET'),
            "google": {
                "client_id": os.getenv('GOOGLE_CLIENT_ID'),
                "client_secret": os.getenv('GOOGLE_CLIENT_SECRET'),
                "server_metadata_url": "https://accounts.google.com/.well-known/openid-configuration",
                "client_kwargs": {
                    "prompt": "select_account"
                }
            }
        }
    }
    
    secrets_singleton._secrets = auth_secrets
    for k, v in auth_secrets.items():
        secrets_singleton._maybe_set_environment_variable(k, v)

# Usage in your app
load_google_config()

if not st.experimental_user.get("is_logged_in", False):
    if st.button("Login with Google"):
        st.login("google")
else:
    if st.button("Log out"):
        st.logout()
    st.write(f"Hello, {st.experimental_user.name}!")

Microsoft Entra ID

Perfect for business apps, especially if your users are already using Microsoft services. Works well with Microsoft 365 and other Microsoft tools.

Click to view setup

Create a .env file with these variables:

REDIRECT_URI=http://localhost:8501/oauth2callback
COOKIE_SECRET=your_secure_cookie_secret
MS_CLIENT_ID=your_microsoft_client_id
MS_CLIENT_SECRET=your_microsoft_client_secret
MS_TENANT_ID=your_tenant_id

Use this Python code for Microsoft authentication:

import streamlit as st
import os
from dotenv import load_dotenv
from streamlit.runtime.secrets import secrets_singleton

def load_microsoft_config():
    """Load Microsoft authentication configuration"""
    load_dotenv()
    
    auth_secrets = {
        "auth": {
            "redirect_uri": os.getenv('REDIRECT_URI'),
            "cookie_secret": os.getenv('COOKIE_SECRET'),
            "microsoft": {
                "client_id": os.getenv('MS_CLIENT_ID'),
                "client_secret": os.getenv('MS_CLIENT_SECRET'),
                "server_metadata_url": f"https://login.microsoftonline.com/{os.getenv('MS_TENANT_ID')}/v2.0/.well-known/openid-configuration",
                "client_kwargs": {
                    "prompt": "select_account"
                }
            }
        }
    }
    
    secrets_singleton._secrets = auth_secrets
    for k, v in auth_secrets.items():
        secrets_singleton._maybe_set_environment_variable(k, v)

# Usage in your app
load_microsoft_config()

if not st.experimental_user.get("is_logged_in", False):
    if st.button("Login with Microsoft"):
        st.login("microsoft")
else:
    if st.button("Log out"):
        st.logout()
    st.write(f"Hello, {st.experimental_user.name}!")

Okta

Built for businesses, Okta helps manage employee access across different applications. Works well if you’re building something for companies that already use Okta.

First you’ll need to create your app integration in the Okta Admin Console

Click to view setup

Create a .env file with these variables:

REDIRECT_URI=http://localhost:8501/oauth2callback
COOKIE_SECRET=your_secure_cookie_secret
OKTA_CLIENT_ID=your_okta_client_id
OKTA_CLIENT_SECRET=your_okta_client_secret
OKTA_SUBDOMAIN=your_okta_subdomain

Use this Python code for Okta authentication:

import streamlit as st
import os
from dotenv import load_dotenv
from streamlit.runtime.secrets import secrets_singleton

def load_okta_config():
    """Load Okta authentication configuration"""
    load_dotenv()
    
    auth_secrets = {
        "auth": {
            "redirect_uri": os.getenv('REDIRECT_URI'),
            "cookie_secret": os.getenv('COOKIE_SECRET'),
            "okta": {
                "client_id": os.getenv('OKTA_CLIENT_ID'),
                "client_secret": os.getenv('OKTA_CLIENT_SECRET'),
                "server_metadata_url": f"https://{os.getenv('OKTA_SUBDOMAIN')}.okta.com/.well-known/openid-configuration",
                "client_kwargs": {
                    "prompt": "login"
                }
            }
        }
    }
    
    secrets_singleton._secrets = auth_secrets
    for k, v in auth_secrets.items():
        secrets_singleton._maybe_set_environment_variable(k, v)

# Usage in your app
load_okta_config()

if not st.experimental_user.get("is_logged_in", False):
    if st.button("Login with Okta"):
        st.login("okta")
else:
    if st.button("Log out"):
        st.logout()
    st.write(f"Hello, {st.experimental_user.name}!")

Auth0

A flexible option that lets you combine different ways of logging in. Good when you want to give users multiple choices for how they sign in.

Click to view setup

Create a .env file with these variables:

REDIRECT_URI=http://localhost:8501/oauth2callback
COOKIE_SECRET=your_secure_cookie_secret
AUTH0_CLIENT_ID=your_auth0_client_id
AUTH0_CLIENT_SECRET=your_auth0_client_secret
AUTH0_DOMAIN=your_account.your_region.auth0.com

Use this Python code for Auth0 authentication:

import streamlit as st
import os
from dotenv import load_dotenv
from streamlit.runtime.secrets import secrets_singleton

def load_auth0_config():
    """Load Auth0 authentication configuration"""
    load_dotenv()
    
    auth_secrets = {
        "auth": {
            "redirect_uri": os.getenv('REDIRECT_URI'),
            "cookie_secret": os.getenv('COOKIE_SECRET'),
            "auth0": {
                "client_id": os.getenv('AUTH0_CLIENT_ID'),
                "client_secret": os.getenv('AUTH0_CLIENT_SECRET'),
                "server_metadata_url": f"https://{os.getenv('AUTH0_DOMAIN')}/.well-known/openid-configuration",
                "client_kwargs": {
                    "prompt": "login"
                }
            }
        }
    }
    
    secrets_singleton._secrets = auth_secrets
    for k, v in auth_secrets.items():
        secrets_singleton._maybe_set_environment_variable(k, v)

# Usage in your app
load_auth0_config()

if not st.experimental_user.get("is_logged_in", False):
    if st.button("Login with Auth0"):
        st.login("auth0")
else:
    if st.button("Log out"):
        st.logout()
    st.write(f"Hello, {st.experimental_user.name}!")

Using Multiple Providers

It is also possible to provide your users with multiple login providers, like Microsoft and Google for example.

Click to view setup

To use multiple providers, combine their environment variables in your .env file:

REDIRECT_URI=http://localhost:8501/oauth2callback
COOKIE_SECRET=your_secure_cookie_secret

# Google configuration
GOOGLE_CLIENT_ID=your_google_client_id
GOOGLE_CLIENT_SECRET=your_google_client_secret

# Microsoft configuration
MS_CLIENT_ID=your_microsoft_client_id
MS_CLIENT_SECRET=your_microsoft_client_secret
MS_TENANT_ID=your_tenant_id

# Add other providers as needed

Here’s how to load multiple providers in your application:

import streamlit as st
import os
from dotenv import load_dotenv
from streamlit.runtime.secrets import secrets_singleton

def load_multi_provider_config():
    """Load configuration for multiple authentication providers"""
    load_dotenv()
    
    auth_secrets = {
        "auth": {
            "redirect_uri": os.getenv('REDIRECT_URI'),
            "cookie_secret": os.getenv('COOKIE_SECRET'),
            "google": {
                "client_id": os.getenv('GOOGLE_CLIENT_ID'),
                "client_secret": os.getenv('GOOGLE_CLIENT_SECRET'),
                "server_metadata_url": "https://accounts.google.com/.well-known/openid-configuration",
                "client_kwargs": {"prompt": "select_account"}
            },
            "microsoft": {
                "client_id": os.getenv('MS_CLIENT_ID'),
                "client_secret": os.getenv('MS_CLIENT_SECRET'),
                "server_metadata_url": f"https://login.microsoftonline.com/{os.getenv('MS_TENANT_ID')}/v2.0/.well-known/openid-configuration",
                "client_kwargs": {"prompt": "select_account"}
            }
            # Add other providers as needed
        }
    }
    
    secrets_singleton._secrets = auth_secrets
    for k, v in auth_secrets.items():
        secrets_singleton._maybe_set_environment_variable(k, v)

# Usage in your app
load_multi_provider_config()

if not st.experimental_user.get("is_logged_in", False):
    st.header("Choose a login provider:")
    col1, col2 = st.columns(2)
    with col1:
        if st.button("Login with Google"):
            st.login("google")
    with col2:
        if st.button("Login with Microsoft"):
            st.login("microsoft")
else:
    if st.button("Log out"):
        st.logout()
    st.write(f"Hello, {st.experimental_user.name}!")

Important considerations:

  • You must install Authlib>=1.3.2 to use authentication
  • The authentication configuration depends on your host location
  • All URLs in the settings must be absolute (starting with http:// or https://)
  • For security reasons, authentication is not supported in embedded apps
  • User sessions automatically expire after 30 days if not logged out
  • Users who are logged in will maintain their session across new tabs in the same browser

Authentication on Ploomber

Ploomber provides multiple authentication options that can be configured directly from the deployment interface, no need to change your code, and it’s compatible with Streamlit, Dash, Shiny & more.

Password Protection

  • Quick setup: Enable password protection directly from the deployment interface
  • Perfect for internal tools and prototypes

Single Sign-On (SSO) Options

  • Microsoft Entra ID integration
  • Google authentication
  • Auth0 support (compatible with any OpenID provider)

Getting Started

  1. Deploy your Streamlit app to Ploomber Cloud
  2. Select your preferred authentication method
  3. Configure your chosen provider
  4. Share your secured app with your team

For detailed setup instructions, visit: