Dash Authorization Package
Dash-auth is a Python library providing HTTP Basic Auth functionality for Dash applications. It enables developers to secure their Dash dashboards with simple username and password authentication. The current version is 2.3.0, and the package is actively maintained by Plotly, focusing on seamless integration within the Dash ecosystem.
Common errors
-
ValueError: too many values to unpack (expected 2)
cause A password supplied in the `VALID_USERNAME_PASSWORD_PAIRS` dictionary or list contains a colon (`:`), which `dash-auth` incorrectly parses as a separator.fixChange the problematic password to remove the colon character. Alternatively, implement a custom `auth_func` for `BasicAuth` that handles password parsing more robustly, rather than relying on the default dictionary/list behavior. -
WARNING:root:Session is not available. Have you set a secret key?
cause The underlying Flask application (which Dash runs on) requires a `SECRET_KEY` for session management, even if `dash-auth` BasicAuth itself doesn't directly use Flask sessions. This warning appears when `app.server.secret_key` is not set.fixSet a unique and strong `secret_key` for your Flask server: `app.server.secret_key = 'your_strong_random_secret_key'`. It is best practice to load this from an environment variable for production. -
dash_auth not working when app is deployed (e.g., on Google Cloud, Heroku, AWS Lambda behind API Gateway)
cause Deployment environments or reverse proxies (like Nginx, AWS API Gateway) might interfere with HTTP Basic Auth headers, such as renaming `WWW-Authenticate` or not passing the `Authorization` header correctly, preventing the browser from prompting for credentials or the app from receiving them.fixCheck your deployment environment's proxy and server configurations. Ensure `WWW-Authenticate` headers are not being stripped or renamed. For AWS API Gateway, a custom authorizer might be needed as API Gateway can rename headers.
Warnings
- gotcha HTTP Basic Auth (provided by dash-auth) has inherent limitations: users cannot log out of applications, cannot create accounts or change passwords, and the authentication prompt is browser-native and not customizable. Credentials are typically hardcoded or managed externally.
- breaking Prior to `dash-auth` version 2.0.0, the library was coupled with `PlotlyAuth` and had imports that caused deprecation warnings with Dash 2.0+ (e.g., `dash_html_components`). `dash-auth` versions < 2.0.0 are not fully compatible with Dash 2.0+.
- gotcha If a password in `VALID_USERNAME_PASSWORD_PAIRS` contains a colon (`:`), `BasicAuth` will fail with a `ValueError: too many values to unpack (expected 2)` because it uses `username_password_utf8.split(':')`.
- gotcha When deploying Dash apps with `dash-auth`, external health check systems expecting a `200 OK` status for the root path might fail. `dash-auth` intentionally returns a `401 Unauthorized` status on initial access to trigger the browser's Basic Auth prompt, which can conflict with simple health checks.
Install
-
pip install dash-auth -
pip install dash>=2.0.0 dash-auth==2.3.0
Imports
- BasicAuth
import dash_auth
from dash_auth import BasicAuth
- Dash
import dash
from dash import Dash
Quickstart
import os
from dash import Dash, html, dcc
from dash_auth import BasicAuth
# Keep this out of source code repository - save in a file or a database
VALID_USERNAME_PASSWORD_PAIRS = {
'dash_user': os.environ.get('DASH_PASSWORD', 's3cr3t_p@ssw0rd!'),
'another_user': 'another_secret_password'
}
app = Dash(__name__)
# Important: Set a secret key for the Flask server to avoid warnings,
# especially if using sessions or other Flask-related features.
# While not strictly required for basic_auth, it's good practice.
app.server.secret_key = os.environ.get('SECRET_KEY', 'a_very_secret_key_that_should_be_randomly_generated')
auth = BasicAuth(app, VALID_USERNAME_PASSWORD_PAIRS)
app.layout = html.Div([
html.H1('Welcome to the Protected Dash App!'),
html.Div('This content is only visible to authenticated users.'),
dcc.Graph(
id='example-graph',
figure={
'data': [
{'x': [1, 2, 3], 'y': [4, 1, 2], 'type': 'bar', 'name': 'SF'},
{'x': [1, 2, 3], 'y': [2, 4, 5], 'type': 'bar', 'name': 'Montréal'},
],
'layout': {
'title': 'Dash Data Visualization'
}
}
)
])
if __name__ == '__main__':
app.run_server(debug=True)