StreamlitAuthenticationSecurityOIDCOAuth

Streamlit Authentication : Guide complet 2025

GP
Gaël Penessot

Streamlit Authentication : Guide complet 2025

L'authentification est essentielle pour sécuriser vos applications Streamlit professionnelles. Que vous créiez un dashboard interne, une app SaaS ou un outil d'entreprise, vous devez contrôler qui accède à vos données.

Depuis Streamlit 1.42.0, l'authentification est devenue beaucoup plus simple grâce aux nouvelles fonctions natives st.login(), st.logout(), et st.user. Fini les librairies tierces complexes !

Dans ce guide, je vais vous montrer toutes les méthodes d'authentification pour Streamlit en 2025, de la plus simple à la plus avancée.

Pourquoi l'authentification est cruciale

Après avoir créé plus de 50 applications Streamlit pour des clients (banques, scale-ups, agences), je peux vous dire que l'authentification est la première question qui revient systématiquement.

Les risques sans authentification

Sans authentification, vos apps Streamlit sont :

  • Accessibles publiquement : N'importe qui avec l'URL peut y accéder
  • Impossibles à auditer : Vous ne savez pas qui fait quoi
  • Non conformes RGPD : Pas de traçabilité des accès aux données personnelles
  • Vulnérables : Exposition de données sensibles

Les bénéfices de l'authentification

Avec une authentification correcte :

  • Contrôle d'accès : Seuls les utilisateurs autorisés peuvent se connecter
  • Personnalisation : Contenu adapté à chaque utilisateur
  • Traçabilité : Logs des accès et actions
  • Conformité : Respect des normes de sécurité (RGPD, SOC2, ISO 27001)

Méthode 1 : Authentification native avec st.login() (Recommandée)

Depuis Streamlit 1.42.0, la méthode officielle pour l'authentification est st.login(). Cette fonction intègre nativement OpenID Connect (OIDC) pour s'authentifier via Google, Microsoft, Okta, Auth0, etc.

Avantages de st.login()

  • Méthode officielle : Supportée et maintenue par Streamlit
  • Sécurisée : OAuth 2.0 + OIDC (standards de l'industrie)
  • Simple : 3 fonctions seulement (st.login(), st.logout(), st.user)
  • Multi-providers : Google, Microsoft, Okta, Auth0, etc.
  • Pas de base de données : Pas besoin de stocker les mots de passe

Installation

pip install streamlit[auth]

Cette commande installe Streamlit avec Authlib>=1.3.2, la librairie nécessaire pour OIDC.

Configuration avec Google (exemple complet)

Étape 1 : Créer une application OAuth sur Google Cloud

  1. Allez sur Google Cloud Console
  2. Créez un nouveau projet ou sélectionnez un projet existant
  3. Activez l'API "Google+ API"
  4. Allez dans APIs & Services > Credentials
  5. Cliquez sur Create Credentials > OAuth 2.0 Client ID
  6. Choisissez Web application
  7. Configurez les Authorized redirect URIs :
    http://localhost:8501/oauth2callback  (pour développement)
    https://votre-app.streamlit.app/oauth2callback  (pour production)
    
  8. Récupérez votre Client ID et Client Secret

Étape 2 : Configurer secrets.toml

Créez le fichier .streamlit/secrets.toml :

[auth]
# URL de redirection après authentification
redirect_uri = "http://localhost:8501/oauth2callback"

# Secret pour signer les cookies (générez-en un aléatoire !)
cookie_secret = "votre_secret_aleatoire_tres_long_et_complexe"

# Credentials Google OAuth
client_id = "votre_client_id.apps.googleusercontent.com"
client_secret = "votre_client_secret"

# URL des métadonnées du serveur OIDC
server_metadata_url = "https://accounts.google.com/.well-known/openid-configuration"

⚠️ IMPORTANT : Générez un cookie_secret fort et aléatoire :

import secrets
print(secrets.token_urlsafe(32))
# Exemple : 'kX9vR3mN2pL7wQ5tY8hJ1fG4dS6aZ0cV'

Étape 3 : Implémenter l'authentification

Voici l'implémentation minimale :

import streamlit as st

# Configuration de la page
st.set_page_config(
    page_title="App Sécurisée",
    page_icon="🔐",
    layout="wide"
)

# Vérifier si l'utilisateur est connecté
if not st.user.is_logged_in:
    st.title("🔐 Authentification requise")
    st.write("Connectez-vous pour accéder à l'application.")

    if st.button("Se connecter avec Google", type="primary"):
        st.login()
else:
    # L'utilisateur est connecté
    st.title("🎉 Bienvenue !")

    # Afficher les informations utilisateur
    col1, col2 = st.columns([3, 1])

    with col1:
        st.write(f"**Nom** : {st.user.name}")
        st.write(f"**Email** : {st.user.email}")
        if hasattr(st.user, 'picture'):
            st.image(st.user.picture, width=100)

    with col2:
        if st.button("Se déconnecter"):
            st.logout()

    st.markdown("---")

    # Contenu de l'application
    st.subheader("📊 Contenu protégé")
    st.write("Seuls les utilisateurs authentifiés peuvent voir ce contenu.")

    # Exemple : afficher toutes les informations de l'utilisateur
    with st.expander("🔍 Informations complètes de l'utilisateur"):
        st.json(st.user.to_dict())

Configuration avec Microsoft Azure AD

Pour Microsoft Entra ID (anciennement Azure AD) :

[auth]
redirect_uri = "http://localhost:8501/oauth2callback"
cookie_secret = "votre_secret_aleatoire"

client_id = "votre_azure_client_id"
client_secret = "votre_azure_client_secret"

# Pour Azure AD
server_metadata_url = "https://login.microsoftonline.com/{tenant_id}/v2.0/.well-known/openid-configuration"

Remplacez {tenant_id} par votre ID de tenant Azure.

Informations disponibles avec Microsoft :

st.user.email                  # Email de l'utilisateur
st.user.name                   # Nom complet
st.user.preferred_username     # Nom d'utilisateur préféré
st.user.oid                    # Object ID (GUID unique)
st.user.tid                    # Tenant ID

Configuration avec Okta

[auth]
redirect_uri = "http://localhost:8501/oauth2callback"
cookie_secret = "votre_secret_aleatoire"

client_id = "votre_okta_client_id"
client_secret = "votre_okta_client_secret"

# Remplacez {your-okta-domain} par votre domaine Okta
server_metadata_url = "https://{your-okta-domain}/.well-known/openid-configuration"

Configuration avec Auth0

[auth]
redirect_uri = "http://localhost:8501/oauth2callback"
cookie_secret = "votre_secret_aleatoire"

client_id = "votre_auth0_client_id"
client_secret = "votre_auth0_client_secret"

# Remplacez {your-auth0-domain} par votre domaine Auth0
server_metadata_url = "https://{your-auth0-domain}/.well-known/openid-configuration"

Utiliser plusieurs providers

Vous pouvez configurer plusieurs providers simultanément :

# Provider par défaut (Google)
[auth]
redirect_uri = "http://localhost:8501/oauth2callback"
cookie_secret = "votre_secret_aleatoire"
client_id = "google_client_id"
client_secret = "google_client_secret"
server_metadata_url = "https://accounts.google.com/.well-known/openid-configuration"

# Provider Microsoft
[auth.microsoft]
redirect_uri = "http://localhost:8501/oauth2callback"
cookie_secret = "votre_secret_aleatoire"
client_id = "microsoft_client_id"
client_secret = "microsoft_client_secret"
server_metadata_url = "https://login.microsoftonline.com/{tenant_id}/v2.0/.well-known/openid-configuration"

# Provider Okta
[auth.okta]
redirect_uri = "http://localhost:8501/oauth2callback"
cookie_secret = "votre_secret_aleatoire"
client_id = "okta_client_id"
client_secret = "okta_client_secret"
server_metadata_url = "https://{okta-domain}/.well-known/openid-configuration"

Dans votre code :

import streamlit as st

if not st.user.is_logged_in:
    st.title("🔐 Choisissez votre méthode de connexion")

    col1, col2, col3 = st.columns(3)

    with col1:
        if st.button("🔵 Google", use_container_width=True):
            st.login()  # Provider par défaut

    with col2:
        if st.button("🟦 Microsoft", use_container_width=True):
            st.login(provider="microsoft")

    with col3:
        if st.button("🟧 Okta", use_container_width=True):
            st.login(provider="okta")
else:
    st.write(f"Connecté en tant que {st.user.email}")
    if st.button("Se déconnecter"):
        st.logout()

Méthode 2 : Authentification simple (mot de passe)

Pour des cas d'usage simples (prototypes, démos internes), vous pouvez utiliser une authentification par mot de passe stockée dans secrets.toml.

Implémentation basique

import streamlit as st
import hashlib

# Fonction pour hasher les mots de passe
def hash_password(password):
    return hashlib.sha256(password.encode()).hexdigest()

# Vérifier l'authentification
def check_password():
    """Retourne True si l'utilisateur est authentifié"""

    # Initialiser session state
    if "authenticated" not in st.session_state:
        st.session_state.authenticated = False

    # Si déjà authentifié
    if st.session_state.authenticated:
        return True

    # Formulaire de connexion
    st.title("🔐 Connexion")

    username = st.text_input("Nom d'utilisateur")
    password = st.text_input("Mot de passe", type="password")

    if st.button("Se connecter", type="primary"):
        # Récupérer les credentials depuis secrets.toml
        users = st.secrets.get("users", {})

        if username in users:
            stored_hash = users[username]["password_hash"]
            input_hash = hash_password(password)

            if stored_hash == input_hash:
                st.session_state.authenticated = True
                st.session_state.username = username
                st.session_state.role = users[username].get("role", "user")
                st.rerun()
            else:
                st.error("❌ Mot de passe incorrect")
        else:
            st.error("❌ Utilisateur inconnu")

    return False

# Utilisation
if check_password():
    st.title(f"👋 Bienvenue {st.session_state.username}")

    if st.button("Se déconnecter"):
        st.session_state.authenticated = False
        st.rerun()

    # Votre application ici
    st.write("Contenu protégé")
else:
    st.stop()

Configuration dans secrets.toml

[users.admin]
password_hash = "8c6976e5b5410415bde908bd4dee15dfb167a9c873fc4bb8a81f6f2ab448a918"  # "admin"
role = "admin"

[users.john]
password_hash = "a665a45920422f9d417e4867efdc4fb8a04a1f3fff1fa07e998e86f7f7a27ae3"  # "123"
role = "user"

Pour générer les hash :

import hashlib
print(hashlib.sha256("votre_mot_de_passe".encode()).hexdigest())

⚠️ Limitations :

  • Les mots de passe sont en clair dans secrets.toml (même hashés, c'est risqué)
  • Pas de gestion des sessions multi-utilisateurs
  • Pas de "mot de passe oublié"
  • Ne convient PAS pour des apps publiques

Méthode 3 : Authentification avec base de données

Pour des applications professionnelles, utilisez une base de données pour stocker les utilisateurs.

Exemple avec PostgreSQL

import streamlit as st
import psycopg2
import hashlib
import bcrypt
from datetime import datetime

# Connexion à la base de données
@st.cache_resource
def get_db_connection():
    return psycopg2.connect(
        host=st.secrets["db"]["host"],
        database=st.secrets["db"]["database"],
        user=st.secrets["db"]["user"],
        password=st.secrets["db"]["password"]
    )

# Vérifier les credentials
def verify_credentials(email, password):
    """Vérifie email et mot de passe dans la base de données"""
    conn = get_db_connection()
    cur = conn.cursor()

    cur.execute(
        "SELECT id, email, password_hash, role, name FROM users WHERE email = %s",
        (email,)
    )
    user = cur.fetchone()
    cur.close()

    if user and bcrypt.checkpw(password.encode(), user[2].encode()):
        return {
            "id": user[0],
            "email": user[1],
            "role": user[3],
            "name": user[4]
        }
    return None

# Log de connexion
def log_login(user_id, success):
    """Enregistre une tentative de connexion"""
    conn = get_db_connection()
    cur = conn.cursor()

    cur.execute(
        """
        INSERT INTO login_logs (user_id, timestamp, success, ip_address)
        VALUES (%s, %s, %s, %s)
        """,
        (user_id, datetime.now(), success, st.context.headers.get("X-Forwarded-For"))
    )
    conn.commit()
    cur.close()

# Interface de connexion
def login_page():
    st.title("🔐 Connexion")

    with st.form("login_form"):
        email = st.text_input("Email")
        password = st.text_input("Mot de passe", type="password")
        submitted = st.form_submit_button("Se connecter", type="primary")

        if submitted:
            user = verify_credentials(email, password)

            if user:
                st.session_state.user = user
                log_login(user["id"], True)
                st.success("✅ Connexion réussie !")
                st.rerun()
            else:
                log_login(None, False)
                st.error("❌ Email ou mot de passe incorrect")

# Vérification de l'authentification
def require_auth():
    """Force l'authentification"""
    if "user" not in st.session_state:
        login_page()
        st.stop()

# Utilisation
require_auth()

# Sidebar avec infos utilisateur
with st.sidebar:
    st.write(f"👤 **{st.session_state.user['name']}**")
    st.write(f"📧 {st.session_state.user['email']}")
    st.write(f"🔑 Role: {st.session_state.user['role']}")

    if st.button("Se déconnecter"):
        del st.session_state.user
        st.rerun()

# Application
st.title("📊 Application sécurisée")
st.write("Contenu accessible uniquement aux utilisateurs authentifiés")

Schema SQL pour la base de données

-- Table des utilisateurs
CREATE TABLE users (
    id SERIAL PRIMARY KEY,
    email VARCHAR(255) UNIQUE NOT NULL,
    password_hash VARCHAR(255) NOT NULL,
    name VARCHAR(255) NOT NULL,
    role VARCHAR(50) DEFAULT 'user',
    created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
    last_login TIMESTAMP
);

-- Table des logs de connexion
CREATE TABLE login_logs (
    id SERIAL PRIMARY KEY,
    user_id INTEGER REFERENCES users(id),
    timestamp TIMESTAMP NOT NULL,
    success BOOLEAN NOT NULL,
    ip_address VARCHAR(45)
);

-- Index pour optimiser les requêtes
CREATE INDEX idx_users_email ON users(email);
CREATE INDEX idx_login_logs_user ON login_logs(user_id);
CREATE INDEX idx_login_logs_timestamp ON login_logs(timestamp);

Script pour créer un utilisateur

import bcrypt
import psycopg2

def create_user(email, password, name, role="user"):
    # Hasher le mot de passe
    password_hash = bcrypt.hashpw(password.encode(), bcrypt.gensalt()).decode()

    # Insérer dans la DB
    conn = psycopg2.connect(...)
    cur = conn.cursor()

    cur.execute(
        """
        INSERT INTO users (email, password_hash, name, role)
        VALUES (%s, %s, %s, %s)
        """,
        (email, password_hash, name, role)
    )

    conn.commit()
    cur.close()
    conn.close()

# Créer un admin
create_user("admin@example.com", "secure_password", "Admin User", "admin")

Gestion des rôles et permissions

Une fois l'authentification en place, vous pouvez implémenter un système de rôles (RBAC - Role-Based Access Control).

Décorateur pour contrôler l'accès

from functools import wraps
import streamlit as st

def require_role(*allowed_roles):
    """Décorateur pour restreindre l'accès par rôle"""
    def decorator(func):
        @wraps(func)
        def wrapper(*args, **kwargs):
            if "user" not in st.session_state:
                st.error("❌ Vous devez être connecté")
                st.stop()

            user_role = st.session_state.user.get("role")

            if user_role not in allowed_roles:
                st.error(f"❌ Accès refusé. Rôle requis : {', '.join(allowed_roles)}")
                st.stop()

            return func(*args, **kwargs)
        return wrapper
    return decorator

# Utilisation
@require_role("admin", "manager")
def admin_dashboard():
    st.title("🔧 Dashboard Admin")
    st.write("Seuls les admins et managers peuvent voir cette page")

    # Fonctionnalités admin
    users_count = get_users_count()
    st.metric("Utilisateurs", users_count)

@require_role("admin")
def manage_users():
    st.title("👥 Gestion des utilisateurs")
    st.write("Seuls les admins peuvent gérer les utilisateurs")

    # CRUD des utilisateurs
    # ...

# Dans votre app
if st.session_state.user["role"] == "admin":
    admin_dashboard()
    manage_users()
else:
    st.info("Vous n'avez pas accès aux fonctionnalités d'administration")

Navigation basée sur les rôles

import streamlit as st

# Définir les pages accessibles par rôle
PAGES_BY_ROLE = {
    "user": ["🏠 Accueil", "📊 Dashboard", "⚙️ Paramètres"],
    "manager": ["🏠 Accueil", "📊 Dashboard", "👥 Équipe", "📈 Rapports", "⚙️ Paramètres"],
    "admin": ["🏠 Accueil", "📊 Dashboard", "👥 Équipe", "📈 Rapports", "🔧 Admin", "⚙️ Paramètres"]
}

# Récupérer les pages accessibles pour l'utilisateur
user_role = st.session_state.user["role"]
available_pages = PAGES_BY_ROLE.get(user_role, PAGES_BY_ROLE["user"])

# Sidebar avec navigation
with st.sidebar:
    st.write(f"👤 {st.session_state.user['name']}")
    st.write(f"🔑 {user_role.upper()}")
    st.markdown("---")

    selected_page = st.radio("Navigation", available_pages)

    st.markdown("---")
    if st.button("Se déconnecter"):
        del st.session_state.user
        st.rerun()

# Afficher la page sélectionnée
if selected_page == "🏠 Accueil":
    home_page()
elif selected_page == "📊 Dashboard":
    dashboard_page()
elif selected_page == "👥 Équipe":
    team_page()
elif selected_page == "📈 Rapports":
    reports_page()
elif selected_page == "🔧 Admin":
    admin_page()
elif selected_page == "⚙️ Paramètres":
    settings_page()

Bonnes pratiques de sécurité

1. Utiliser HTTPS en production

⚠️ CRITIQUE : Toujours utiliser HTTPS en production pour protéger les cookies de session.

Sur Streamlit Cloud, HTTPS est activé par défaut. Sur votre propre serveur, configurez un reverse proxy (nginx, Caddy) avec certificat SSL.

2. Expiration des sessions

Avec st.login(), les cookies expirent après 30 jours d'inactivité. Vous pouvez implémenter une expiration personnalisée :

from datetime import datetime, timedelta

# Vérifier l'expiration du token
if st.user.is_logged_in:
    exp = st.user.get("exp")  # Timestamp d'expiration

    if exp and datetime.fromtimestamp(exp) < datetime.now():
        st.warning("⚠️ Votre session a expiré")
        st.logout()
        st.stop()

3. Protection contre les attaques brute-force

Limitez le nombre de tentatives de connexion :

import time
from datetime import datetime, timedelta

# Initialiser le compteur
if "login_attempts" not in st.session_state:
    st.session_state.login_attempts = 0
    st.session_state.last_attempt = None

def login_with_rate_limit(email, password):
    # Vérifier le rate limiting
    if st.session_state.login_attempts >= 5:
        if st.session_state.last_attempt:
            time_elapsed = (datetime.now() - st.session_state.last_attempt).seconds
            if time_elapsed < 300:  # 5 minutes
                wait_time = 300 - time_elapsed
                st.error(f"❌ Trop de tentatives. Réessayez dans {wait_time // 60} minutes.")
                return False
            else:
                # Reset après 5 minutes
                st.session_state.login_attempts = 0

    # Tenter la connexion
    user = verify_credentials(email, password)

    if user:
        st.session_state.login_attempts = 0
        st.session_state.user = user
        return True
    else:
        st.session_state.login_attempts += 1
        st.session_state.last_attempt = datetime.now()
        return False

4. Ne jamais stocker de secrets en clair

❌ Mauvais :

# secrets.toml
password = "mon_mot_de_passe"  # EN CLAIR !

✅ Bon :

# secrets.toml
password_hash = "5e884898da28047151d0e56f8dc6292773603d0d6aabbdd62a11ef721d1542d8"

5. Logs d'audit

Tracez toutes les actions importantes :

def log_action(user_id, action, details=None):
    """Enregistre une action utilisateur"""
    conn = get_db_connection()
    cur = conn.cursor()

    cur.execute(
        """
        INSERT INTO audit_logs (user_id, action, details, timestamp, ip_address)
        VALUES (%s, %s, %s, %s, %s)
        """,
        (user_id, action, details, datetime.now(), get_client_ip())
    )

    conn.commit()
    cur.close()

# Utilisation
log_action(st.session_state.user["id"], "view_sensitive_data", "Customer database")
log_action(st.session_state.user["id"], "export_data", "Q4 sales report")

Erreurs courantes à éviter

1. Oublier st.stop() après redirection

❌ Mauvais :

if not st.user.is_logged_in:
    st.login()
    # Le code continue à s'exécuter !

st.write("Contenu protégé")  # Visible même non connecté !

✅ Bon :

if not st.user.is_logged_in:
    st.login()
    st.stop()  # Arrête l'exécution

st.write("Contenu protégé")

2. Ne pas sécuriser les secrets en production

Sur Streamlit Cloud, utilisez les Secrets dans le dashboard :

  1. Allez dans votre app sur Streamlit Cloud
  2. Settings > Secrets
  3. Collez votre configuration secrets.toml

Ne commitez JAMAIS secrets.toml dans Git !

3. Utiliser session_state sans vérification

❌ Mauvais :

st.write(f"Hello {st.session_state.user['name']}")  # KeyError si non connecté !

✅ Bon :

if "user" in st.session_state:
    st.write(f"Hello {st.session_state.user['name']}")
else:
    st.write("Veuillez vous connecter")

4. Ne pas valider les inputs utilisateur

❌ Mauvais :

email = st.text_input("Email")
# Pas de validation !
verify_credentials(email, password)

✅ Bon :

import re

email = st.text_input("Email")

if email and not re.match(r"[^@]+@[^@]+\.[^@]+", email):
    st.error("❌ Format d'email invalide")
    st.stop()

verify_credentials(email, password)

Déploiement sécurisé

Sur Streamlit Cloud

  1. Configurer les secrets :

    • Dashboard > Settings > Secrets
    • Coller votre configuration OIDC
  2. Configurer le redirect_uri :

    redirect_uri = "https://votre-app.streamlit.app/oauth2callback"
  3. Activer HTTPS (activé par défaut sur Streamlit Cloud)

Sur votre propre serveur

Utilisez Docker + nginx :

# Dockerfile
FROM python:3.11-slim

WORKDIR /app

COPY requirements.txt .
RUN pip install -r requirements.txt

COPY . .

EXPOSE 8501

CMD ["streamlit", "run", "app.py", "--server.port=8501", "--server.address=0.0.0.0"]

Configuration nginx :

server {
    listen 80;
    server_name votre-domaine.com;
    return 301 https://$server_name$request_uri;
}

server {
    listen 443 ssl;
    server_name votre-domaine.com;

    ssl_certificate /etc/letsencrypt/live/votre-domaine.com/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/votre-domaine.com/privkey.pem;

    location / {
        proxy_pass http://localhost:8501;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto $scheme;

        # WebSocket support
        proxy_http_version 1.1;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection "upgrade";
    }
}

Cas d'usage réels

Voici 3 implémentations que j'ai réalisées pour des clients :

1. Dashboard interne (Startup SaaS)

  • Authentification : Google OAuth via st.login()
  • Utilisateurs : 15 employés
  • Rôles : admin, sales, support
  • Impact : Réduction de 80% du temps de configuration (vs solution custom)

2. Plateforme d'analyse (Banque)

  • Authentification : Microsoft Azure AD
  • Utilisateurs : 200+ analystes
  • Rôles : viewer, analyst, admin
  • Compliance : Logs d'audit complets, expiration de session à 30 min
  • Impact : Conformité SOC2 + RGPD

3. App de reporting client (Agence)

  • Authentification : Base de données PostgreSQL
  • Utilisateurs : 50+ clients externes
  • Rôles : client, agency_user, admin
  • Fonctionnalités : Chaque client voit uniquement ses données
  • Impact : +40% d'engagement client (vs PDF statiques)

Ressources complémentaires

Documentation officielle

Mes formations

Pour maîtriser Streamlit de A à Z, découvrez ma formation complète :

👉 Streamlit Unleashed - 20h de contenu, 50+ exercices pratiques, section complète sur la sécurité et l'authentification

Outils gratuits

Librairies utiles

  • Authlib : Librairie OAuth/OIDC utilisée par st.login()
  • bcrypt : Hashing sécurisé de mots de passe
  • PyJWT : Validation de tokens JWT

Conclusion

L'authentification sur Streamlit est devenue beaucoup plus simple en 2025 grâce à st.login(). Voici mes recommandations :

Pour des apps internes (< 50 utilisateurs) : ✅ Utilisez st.login() avec Google ou Microsoft OAuth

Pour des apps professionnelles (50-500 utilisateurs) : ✅ Utilisez st.login() avec un provider d'entreprise (Okta, Azure AD) ✅ Ajoutez un système de rôles (RBAC) ✅ Implémentez des logs d'audit

Pour des apps SaaS (500+ utilisateurs) : ✅ Base de données dédiée avec bcrypt ✅ Système de rôles avancé ✅ Logs d'audit complets ✅ Rate limiting sur les connexions ✅ Sessions avec expiration courte

Checklist de sécurité :

  • ✅ HTTPS obligatoire en production
  • ✅ Secrets stockés dans .streamlit/secrets.toml (jamais dans le code)
  • ✅ Mots de passe hashés avec bcrypt (jamais en clair)
  • ✅ Rate limiting sur les tentatives de connexion
  • ✅ Logs d'audit pour toutes les actions critiques
  • ✅ Validation des inputs utilisateur
  • ✅ Expiration automatique des sessions

L'authentification n'est plus un obstacle pour créer des applications Streamlit professionnelles et sécurisées. Avec les bonnes pratiques de ce guide, vous pouvez déployer des apps conformes aux standards de l'industrie.

Prochaines étapes :

  1. Choisissez votre méthode d'authentification
  2. Configurez votre provider OAuth (ou votre DB)
  3. Implémentez st.login() dans votre app
  4. Testez en local puis déployez sur Streamlit Cloud

Des questions sur l'authentification Streamlit ? Contactez-moi sur LinkedIn ou par email à gael@mes-formations-data.fr.


Cet article fait partie de ma série complète sur Streamlit. Pour aller plus loin :

Livre Business Intelligence avec Python

📚 Approfondir avec mon livre

"Business Intelligence avec Python" - Le guide complet pour maîtriser l'analyse de données

Voir sur Amazon →

📬 Ne manquez rien de l'actualité data

Rejoignez +1000 professionnels qui reçoivent chaque semaine mes analyses, conseils et découvertes data.

S'abonner gratuitement
Prochaine révision : Trimestre prochain