<?xml version="1.0" encoding="UTF-8"?><rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>Archives des dash-auth | dash-resources.com</title>
	<atom:link href="https://dash-resources.com/tag/dash-auth/feed/" rel="self" type="application/rss+xml" />
	<link>https://dash-resources.com/tag/dash-auth/</link>
	<description>Learn to build interactive web applications with Python and Dash plotly</description>
	<lastBuildDate>Thu, 28 Aug 2025 08:57:25 +0000</lastBuildDate>
	<language>en-US</language>
	<sy:updatePeriod>
	hourly	</sy:updatePeriod>
	<sy:updateFrequency>
	1	</sy:updateFrequency>
	<generator>https://wordpress.org/?v=6.9.1</generator>

<image>
	<url>https://dash-resources.com/wp-content/uploads/2024/12/cropped-dash-logo-favicon-512-32x32.png</url>
	<title>Archives des dash-auth | dash-resources.com</title>
	<link>https://dash-resources.com/tag/dash-auth/</link>
	<width>32</width>
	<height>32</height>
</image> 
	<item>
		<title>How to secure a multi-page Dash app with dash-auth</title>
		<link>https://dash-resources.com/how-to-secure-a-multi-page-dash-app-with-dash-auth/</link>
		
		<dc:creator><![CDATA[Fran]]></dc:creator>
		<pubDate>Thu, 28 Aug 2025 08:44:53 +0000</pubDate>
				<category><![CDATA[Beginner level]]></category>
		<category><![CDATA[dash-auth]]></category>
		<category><![CDATA[tutorial]]></category>
		<guid isPermaLink="false">https://dash-resources.com/?p=926</guid>

					<description><![CDATA[<p>In this tutorial, we will see how to secure your Dash multi-page app using the basic authentication mechanism in dash-auth. It’s the natural continuation of [...]</p>
<p>L’article <a href="https://dash-resources.com/how-to-secure-a-multi-page-dash-app-with-dash-auth/">How to secure a multi-page Dash app with dash-auth</a> est apparu en premier sur <a href="https://dash-resources.com">dash-resources.com</a>.</p>
]]></description>
										<content:encoded><![CDATA[
<p>In this tutorial, we will see how to secure your <a href="https://dash.plotly.com/urls">Dash multi-page</a> app using the basic authentication mechanism in <code>dash-auth</code>.</p>



<p>It’s the natural continuation of the previous tutorial: <a href="https://dash-resources.com/how-to-secure-your-dash-app-with-dash-auth/">How to secure a Dash app with dash-auth</a>, where you can learn how to use <code>dash-auth</code>, connect to a database, and display the username.</p>


        
            
            <div class="fit_content">
                <div class="bd_toc_container" data-fixedWidth="">
                    <div class="bd_toc_wrapper" data-wrapperPadding="48px">
                        <div class="bd_toc_wrapper_item">
                            <div class="bd_toc_header active" data-headerPadding="2px">
                                <div class="bd_toc_header_title">
                                    Table of Contents                                </div>
                                <div class="bd_toc_switcher_hide_show_icon">
                                    <span class="bd_toc_arrow"></span>                                </div>
                            </div>
                            <div class="bd_toc_content list-type-disc">
                                <div class="bd_toc_content_list ">
                                    <div class='bd_toc_content_list_item'>    <ul>
      <li class="first">
        <a href="#dash-auth">Dash-auth</a>
        <ul class="menu_level_2">
          <li class="first">
            <a href="#app-py">app.py</a>
          </li>
          <li>
            <a href="#pages-public-py">pages/public.py</a>
          </li>
          <li class="last">
            <a href="#pages-private-py">pages/private.py</a>
          </li>
        </ul>
      </li>
      <li>
        <a href="#result">Result</a>
      </li>
      <li class="last">
        <a href="#conclusion">Conclusion</a>
      </li>
    </ul>
</div>                                </div>
                            </div>
                        </div>
                    </div>
                    <div class="layout_toggle_button">
                        <span class="bd_toc_arrow"></span>
                    </div>
                </div>
            </div>




<p>Let’s go! </p>



<h2 id='dash-auth'  id="boomdevs_1" class="wp-block-heading" >Dash-auth</h2>



<p>If you haven’t yet, install <code>dash</code> and <code>dash-auth</code>:</p>



<pre class="wp-block-code"><code lang="python" class="language-python">pip install dash dash-auth
</code></pre>



<p>Then, create three files and one folder:</p>



<ul class="wp-block-list">
<li><code>app.py</code>: the main app file</li>



<li><code>pages/public.py</code>: the publicly accessible page at URL &#8220;/&#8221;</li>



<li><code>pages/private.py</code>: the private page at URL &#8220;/private&#8221;</li>
</ul>



<h3 id='app-py'  id="boomdevs_2" class="wp-block-heading" >app.py</h3>



<p>This file will be very similar to what we had in the previous tutorial. The list of users is hardcoded at the beginning of the file:</p>



<pre class="wp-block-code"><code lang="python" class="language-python">from dash import Dash, html, dcc, page_container
import dash_auth

# Note: better store the list in a secrets file or in a database.
USERS = {
    "alice": "secret123",
    "bob": "pa$$w0rd"
}

# Create the Dash app
app = Dash(
    __name__,
    use_pages=True,
    suppress_callback_exceptions=True
)

# Add authentication
auth = dash_auth.BasicAuth(
    app,
    username_password_list=USERS,
    secret_key="something_like_nUGz8DZvb...",
    # Public routes are not protected by authentication.
    # All others are protected by default
    public_routes=["/"]
)

# Define the layout
app.layout = html.Div([
    html.H1("My app"),
    html.P(dcc.Link("Public page", href="/")),
    html.P(dcc.Link("Private page", href="/private")),
    html.Hr(),
    page_container
])

if __name__ == '__main__':
    app.run(debug=True)

</code></pre>



<p>There are two key differences:</p>



<ul class="wp-block-list">
<li>We use pages for the Dash app (<code>use_pages=True</code> and <code>suppress_callback_exceptions=True</code>)</li>



<li>We define the public pages in Dash-auth using <code>public_routes</code>.</li>
</ul>



<p>Then, the layout shows two links to the two pages and the page content (using <code>page_container</code>).</p>



<h3 id='pages-public-py'  id="boomdevs_3" class="wp-block-heading" >pages/public.py</h3>



<p>The public page will contain a button that increments itself when clicked:</p>



<pre class="wp-block-code"><code lang="python" class="language-python">from dash import html, dcc, register_page, callback, Output, Input
from dash_auth import public_callback

# The public page is the home
register_page(
    __name__,
    "/",
)

# The page layout
def layout():
    return html.Div([
        html.P("This is a public page."),
        html.Button("Click me (0)", id="button", n_clicks=0)
    ])

# A simple public callback
@public_callback(
    Output("button", "children"),
    Input("button", "n_clicks"),
)
def update_button(n_clicks):
    return f"Click me ({n_clicks})"

</code></pre>



<p>The only key change here is the use of <code>public_callback</code> (from <code>dash-auth</code>) instead of <code>callback</code>.</p>


<div class="wp-block-image">
<figure class="aligncenter size-large is-resized"><img fetchpriority="high" decoding="async" width="1024" height="508" src="https://dash-resources.com/wp-content/uploads/2025/08/image-3-1024x508.png" alt="" class="wp-image-929" style="width:553px;height:auto" srcset="https://dash-resources.com/wp-content/uploads/2025/08/image-3-1024x508.png 1024w, https://dash-resources.com/wp-content/uploads/2025/08/image-3-300x149.png 300w, https://dash-resources.com/wp-content/uploads/2025/08/image-3-768x381.png 768w, https://dash-resources.com/wp-content/uploads/2025/08/image-3.png 1168w" sizes="(max-width: 1024px) 100vw, 1024px" /><figcaption class="wp-element-caption">The public, unprotected page</figcaption></figure>
</div>


<p class="callout">By default, all callbacks use the same URL endpoint: <code>/dash-update-component</code>. This is why we need to specify that this callback is public, while others are protected by default as soon as we add <code>dash-auth</code> to the app.<br><br>Under the hood, the callback ID is simply added to a list of whitelisted callbacks in the Flask server’s config.</p>



<h3 id='pages-private-py'  id="boomdevs_4" class="wp-block-heading" >pages/private.py</h3>



<p>The private page will only show the username using a layout function:</p>



<pre class="wp-block-code"><code lang="python" class="language-python">from dash import html, register_page
import flask

register_page(
    __name__,
    "/private",
)

def layout():
    username = flask.session.get("user").get("email")

    return html.Div([
        html.P("If you see this, you are authenticated <img src="https://s.w.org/images/core/emoji/17.0.2/72x72/2705.png" alt="✅" class="wp-smiley" style="height: 1em; max-height: 1em;" />"),
        html.P(f"You are logged in as {username}.")
    ])
</code></pre>


<div class="wp-block-image">
<figure class="aligncenter size-large is-resized"><img decoding="async" width="1024" height="530" src="https://dash-resources.com/wp-content/uploads/2025/08/image-4-1024x530.png" alt="" class="wp-image-930" style="width:565px;height:auto" srcset="https://dash-resources.com/wp-content/uploads/2025/08/image-4-1024x530.png 1024w, https://dash-resources.com/wp-content/uploads/2025/08/image-4-300x155.png 300w, https://dash-resources.com/wp-content/uploads/2025/08/image-4-768x398.png 768w, https://dash-resources.com/wp-content/uploads/2025/08/image-4.png 1136w" sizes="(max-width: 1024px) 100vw, 1024px" /><figcaption class="wp-element-caption">The private page, protected by HTTP basic authentification.</figcaption></figure>
</div>


<p><code>dash-auth</code> saves the current username in a flask cookie, so we can get easily get it in the layout function, or within a callback.</p>



<h2 id='result'  id="boomdevs_5" class="wp-block-heading" >Result</h2>



<p>Now let’s run this app!<br>Here is a little video of what it looks like:</p>



<figure class="wp-block-video"><video height="852" style="aspect-ratio: 1386 / 852;" width="1386" controls src="https://dash-resources.com/wp-content/uploads/2025/08/dash-auth-pages.mp4"></video></figure>



<p><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/26a0.png" alt="⚠" class="wp-smiley" style="height: 1em; max-height: 1em;" />&nbsp;Note that once we’re logged in, we can’t log out manually. The browser must be closed instead.</p>



<h2 id='conclusion'  id="boomdevs_6" class="wp-block-heading" >Conclusion</h2>



<p>I hope this tutorial was instructive! I found it interesting that <code>dash-auth</code> evolved to secure multi-page apps as well, which I didn’t know until writing these two tutorials <img src="https://s.w.org/images/core/emoji/17.0.2/72x72/1f642.png" alt="🙂" class="wp-smiley" style="height: 1em; max-height: 1em;" /></p>



<p>As with the <a href="https://dash-resources.com/how-to-secure-your-dash-app-with-dash-auth/">previous tutorial</a>, the conclusion is similar: <code>dash-auth</code> has its drawbacks, but it’s a <strong>fairly easy solution</strong> to add an authentication layer to a dashboard or a data app. However, I would <strong>not recommend</strong> using it for production apps that have very sensitive data.</p>



<p>If you need proper login/logout behavior (e.g., session expiration, multiple users switching), you’ll need a more advanced system such as:</p>



<ul class="wp-block-list">
<li><code>flask_login</code></li>



<li>OAuth (Google, GitHub…)</li>



<li>Enterprise identity providers (Okta, Auth0, Azure AD…)</li>



<li><a href="https://plotly.com/dash/authentication/">Dash-Enterprise</a> (handles LDAP, SAML, OIDC)</li>
</ul>



<p>Happy Dash coding!</p>



<p></p>
<p>L’article <a href="https://dash-resources.com/how-to-secure-a-multi-page-dash-app-with-dash-auth/">How to secure a multi-page Dash app with dash-auth</a> est apparu en premier sur <a href="https://dash-resources.com">dash-resources.com</a>.</p>
]]></content:encoded>
					
		
		<enclosure url="https://dash-resources.com/wp-content/uploads/2025/08/dash-auth-pages.mp4" length="363032" type="video/mp4" />

			</item>
		<item>
		<title>How to secure a Dash app with dash-auth</title>
		<link>https://dash-resources.com/how-to-secure-your-dash-app-with-dash-auth/</link>
		
		<dc:creator><![CDATA[Fran]]></dc:creator>
		<pubDate>Thu, 28 Aug 2025 08:37:01 +0000</pubDate>
				<category><![CDATA[Beginner level]]></category>
		<category><![CDATA[dash-auth]]></category>
		<category><![CDATA[tutorial]]></category>
		<guid isPermaLink="false">https://dash-resources.com/?p=918</guid>

					<description><![CDATA[<p>In this tutorial, we’ll see how you can protect your Dash app with the package dash-auth. We’ll cover how to set up basic authentication, how [...]</p>
<p>L’article <a href="https://dash-resources.com/how-to-secure-your-dash-app-with-dash-auth/">How to secure a Dash app with dash-auth</a> est apparu en premier sur <a href="https://dash-resources.com">dash-resources.com</a>.</p>
]]></description>
										<content:encoded><![CDATA[
<p>In this tutorial, we’ll see how you can protect your Dash app with the package <code>dash-auth</code>.</p>



<p>We’ll cover how to set up basic authentication, how to define a custom authentication function, and even how to connect it to a database.</p>


        
            
            <div class="fit_content">
                <div class="bd_toc_container" data-fixedWidth="">
                    <div class="bd_toc_wrapper" data-wrapperPadding="48px">
                        <div class="bd_toc_wrapper_item">
                            <div class="bd_toc_header active" data-headerPadding="2px">
                                <div class="bd_toc_header_title">
                                    Table of Contents                                </div>
                                <div class="bd_toc_switcher_hide_show_icon">
                                    <span class="bd_toc_arrow"></span>                                </div>
                            </div>
                            <div class="bd_toc_content list-type-disc">
                                <div class="bd_toc_content_list ">
                                    <div class='bd_toc_content_list_item'>    <ul>
      <li class="first">
        <a href="#basic-dash-auth">Basic Dash auth</a>
      </li>
      <li>
        <a href="#retrieve-the-user">Retrieve the user</a>
      </li>
      <li>
        <a href="#authentication-function">Authentication function</a>
        <ul class="menu_level_2">
          <li class="first">
            <a href="#comparing-hashed-passwords">Comparing hashed passwords</a>
          </li>
          <li class="last">
            <a href="#use-a-database">Use a database</a>
          </li>
        </ul>
      </li>
      <li>
        <a href="#why-you-can-t-logout">Why you can’t logout</a>
      </li>
      <li class="last">
        <a href="#conclusion">Conclusion</a>
      </li>
    </ul>
</div>                                </div>
                            </div>
                        </div>
                    </div>
                    <div class="layout_toggle_button">
                        <span class="bd_toc_arrow"></span>
                    </div>
                </div>
            </div>




<p>Let’s go! <img src="https://s.w.org/images/core/emoji/17.0.2/72x72/2b07.png" alt="⬇" class="wp-smiley" style="height: 1em; max-height: 1em;" /></p>



<h2 id='basic-dash-auth'  id="boomdevs_1" class="wp-block-heading" >Basic Dash auth</h2>



<p>First, install Dash and Dash Auth:</p>



<pre class="wp-block-code"><code lang="python" class="language-python">pip install dash dash-auth</code></pre>



<p>Next, define a list of users and their associated passwords:</p>



<pre class="wp-block-code"><code lang="python" class="language-python">from dash import Dash, html
import dash_auth

# <img src="https://s.w.org/images/core/emoji/17.0.2/72x72/26a0.png" alt="⚠" class="wp-smiley" style="height: 1em; max-height: 1em;" /> Defining passwords directly in code is a bad practice.
# Better: store them in a secrets file or a database.
USERS = {
    "alice": "secret123",
    "bob": "pa$$w0rd"
}

# Create the Dash app
app = Dash(__name__)

# Add authentication
auth = dash_auth.BasicAuth(
    app,
    username_password_list=USERS,
    # Set the secret key to something random.
    secret_key="something_like_nUGz8DZvb..."
)

# Define the layout
app.layout = html.Div([
    html.H1("Protected app"),
    html.P("If you see this, you are authenticated <img src="https://s.w.org/images/core/emoji/17.0.2/72x72/2705.png" alt="✅" class="wp-smiley" style="height: 1em; max-height: 1em;" />")
])

if __name__ == '__main__':
    app.run(debug=True)
</code></pre>



<p>The secret key must be unique and… secret <img src="https://s.w.org/images/core/emoji/17.0.2/72x72/1f609.png" alt="😉" class="wp-smiley" style="height: 1em; max-height: 1em;" />.<br>To generate one, run this in your terminal:</p>



<pre class="wp-block-code"><code lang="python" class="language-python">python -c "import secrets; print(secrets.token_urlsafe(32))"
</code></pre>



<p class="callout"><strong>Note:</strong> the <code>secret_key</code> isn’t mandatory for <code>dash-auth</code> since it doesn’t use cookies. However, adding it removes the warning: “<em>WARNING:root:Session is not available. Have you set a secret key?</em>”.</p>



<p>Then, just run your app with <code>python app.py</code>. You should get this result:</p>



<figure class="wp-block-image size-full"><img decoding="async" width="1824" height="1144" src="https://dash-resources.com/wp-content/uploads/2025/08/image.png" alt="" class="wp-image-919" srcset="https://dash-resources.com/wp-content/uploads/2025/08/image.png 1824w, https://dash-resources.com/wp-content/uploads/2025/08/image-300x188.png 300w, https://dash-resources.com/wp-content/uploads/2025/08/image-1024x642.png 1024w, https://dash-resources.com/wp-content/uploads/2025/08/image-768x482.png 768w, https://dash-resources.com/wp-content/uploads/2025/08/image-1536x963.png 1536w" sizes="(max-width: 1824px) 100vw, 1824px" /></figure>



<p>And after log-in:</p>



<figure class="wp-block-image size-full"><img loading="lazy" decoding="async" width="1630" height="1058" src="https://dash-resources.com/wp-content/uploads/2025/08/image-1.png" alt="" class="wp-image-920" srcset="https://dash-resources.com/wp-content/uploads/2025/08/image-1.png 1630w, https://dash-resources.com/wp-content/uploads/2025/08/image-1-300x195.png 300w, https://dash-resources.com/wp-content/uploads/2025/08/image-1-1024x665.png 1024w, https://dash-resources.com/wp-content/uploads/2025/08/image-1-768x498.png 768w, https://dash-resources.com/wp-content/uploads/2025/08/image-1-1536x997.png 1536w" sizes="auto, (max-width: 1630px) 100vw, 1630px" /></figure>



<p>That’s it! You get a protected page. <img src="https://s.w.org/images/core/emoji/17.0.2/72x72/1f929.png" alt="🤩" class="wp-smiley" style="height: 1em; max-height: 1em;" /></p>



<p>There are some <strong>limitations</strong>:</p>



<ul class="wp-block-list">
<li>You cannot customize the login/password popup window, it’s natively handled by the browser.</li>



<li>Users cannot logout: the session is active until they close their browser.</li>



<li>The list of users is fixed: you will need to reload the app to add or remove a user or update a password.</li>
</ul>



<h2 id='retrieve-the-user'  id="boomdevs_2" class="wp-block-heading" >Retrieve the user</h2>



<p>The user information is stored in the <code>flask.session</code> object. It’s therefore easy to retrieve it in a callback:</p>



<pre class="wp-block-code"><code lang="python" class="language-python"># ...

# Define the layout
app.layout = html.Div([
    html.H1("Protected app"),
    html.P("If you see this, you are authenticated <img src="https://s.w.org/images/core/emoji/17.0.2/72x72/2705.png" alt="✅" class="wp-smiley" style="height: 1em; max-height: 1em;" />"),
    html.P(id="user_info")  # added this
])

# Define the callback
@app.callback(
    Output("user_info", "children"),
    Input("user_info", "id"),  # dummy trigger
)
def update_user_info(_):
    """ Display the username of the logged in user. """
    username = flask.session.get("user").get("email")
    return f"You are logged in as {username}."

if __name__ == '__main__':
    app.run(debug=True)
</code></pre>



<p>Let’s explain this code:</p>



<ul class="wp-block-list">
<li>I added a new paragraph #user_info</li>



<li>A new callback is triggered at initialization time. It displays the username.</li>
</ul>



<p>Now let’s see the result:</p>



<figure class="wp-block-image size-full"><img loading="lazy" decoding="async" width="1630" height="1058" src="https://dash-resources.com/wp-content/uploads/2025/08/image-2.png" alt="" class="wp-image-923" srcset="https://dash-resources.com/wp-content/uploads/2025/08/image-2.png 1630w, https://dash-resources.com/wp-content/uploads/2025/08/image-2-300x195.png 300w, https://dash-resources.com/wp-content/uploads/2025/08/image-2-1024x665.png 1024w, https://dash-resources.com/wp-content/uploads/2025/08/image-2-768x498.png 768w, https://dash-resources.com/wp-content/uploads/2025/08/image-2-1536x997.png 1536w" sizes="auto, (max-width: 1630px) 100vw, 1630px" /></figure>



<h2 id='authentication-function'  id="boomdevs_3" class="wp-block-heading" >Authentication function</h2>



<p>It’s possible to use an arbitrary python function to handle authentication. This is useful to:</p>



<ul class="wp-block-list">
<li>store and compare hashed passwords instead of plain passwords;</li>



<li>retrieve user information and passwords from a database.</li>
</ul>



<h3 id='comparing-hashed-passwords'  id="boomdevs_4" class="wp-block-heading" >Comparing hashed passwords</h3>



<p>Storing passwords in clear in the code is a pretty bad practice for security and confidentiality reasons. Instead, a better practice is to store hashed passwords instead of the clear version. If the password leaks, the original password can&#8217;t be found!</p>



<p>You can hash a password using the <code>generate_password_hash</code> from <code>werkzeug.security</code> package. For instance:</p>



<pre class="wp-block-code"><code lang="python" class="language-python">from werkzeug.security import generate_password_hash
print(generate_password_hash("secret123"))
# scrypt:32768:8:1$PICpPDH9JdIz75DT$d5f81a560015a407e51989f03d046816954ba2b8d5ee520b999f492352b9e8a39084210ea2fe3bfdcdc2a94047a5397e04bbf3663b505967d3d1ea91a95101d7'
</code></pre>



<p>Then, we can compare the two password hashes with the <code>check_password_hash</code> function:</p>



<pre class="wp-block-code"><code lang="python" class="language-python">
from werkzeug.security import check_password_hash

def auth_func(username, password):
    """ Authenticate the user using hashed passwords. """

    # Check the user exists and the password is correct
    if username in USERS and check_password_hash(USERS[username], password):
        return True
    return False
</code></pre>



<p>That&#8217;s it. We just check the user exists, and compare its hash.</p>



<p>Let&#8217;s put this all together and replace the <code>USERS</code> list with the <code>auth_func</code> parameter:</p>



<pre class="wp-block-code"><code lang="python" class="language-python">from dash import Dash, html
from dash_auth import BasicAuth
from werkzeug.security import generate_password_hash, check_password_hash

# This time, we store hashed passwords. 
# Meaning that they can't be compromised if our code leaks.
USERS = {
    "alice": "scrypt:32768:8:1$HtB7iBw3ZGspBOHX$36879fd912db96322af2c33c3eb3fd0142ca2ec51988f332cc477b89c012449e5562487b410264b02d495d785780d0099e9130b42c4f61d7bc9166b93f7d1626",
    "bob": "scrypt:32768:8:1$j2rFpuXSr2D5t4Ij$9436a942b25f93054d3c96e54dcdd342c97f86515e09aafecd564984c22beb991029b70a89164215590ec131be4e13a12e043f4572ceb06576f86f925b1b9d65"
}

def auth_func(username, password):
    """ Authenticate the user using hashed passwords. """
    if username in USERS and check_password_hash(USERS[username], password):
        return True
    return False

app = Dash(__name__)
auth = BasicAuth(
    app, 
    auth_func=auth_func, # We now use auth_func in place of the user list.
    secret_key="something_like_nUGz8DZvb..."
)

app.layout = html.Div([
    html.H1("Protected app"),
    html.P("If you see this, you are authenticated.")
])

if __name__ == "__main__":
    app.run(debug=True)
</code></pre>



<p>The result is visually the same for the user, but now passwords are not stored in clear. It also means that the original passwords are not shared with the developers having access to the Dash app code.</p>



<p>Much better! <img src="https://s.w.org/images/core/emoji/17.0.2/72x72/1f642.png" alt="🙂" class="wp-smiley" style="height: 1em; max-height: 1em;" /></p>



<h3 id='use-a-database'  id="boomdevs_5" class="wp-block-heading" >Use a database</h3>



<p>We can also use the authentication function to request an external database. The good thing with this solution is that the list of users can be dynamically managed.</p>



<p>Let&#8217;s create a simple script to initialize a <code>sqlite</code> database:</p>



<pre class="wp-block-code"><code lang="python" class="language-python"># init_db.py
import sqlite3
from werkzeug.security import generate_password_hash

DB_PATH = "users.db"

def init_db():
    """Create a tiny users table and seed two demo users if empty."""
    with sqlite3.connect(DB_PATH) as con:
        cur = con.cursor()
        cur.execute("""
            DROP TABLE IF EXISTS users;
            CREATE TABLE users (
                username TEXT PRIMARY KEY,
                password_hash TEXT NOT NULL,
                language TEXT NOT NULL
            )
        """)

        # Insert values
        cur.executemany(
            "INSERT INTO users(username, password_hash, language) VALUES (?, ?, ?)",
            [
                ("alice", generate_password_hash("secret123"), "en"),
                ("bob",   generate_password_hash("pa$$w0rd"), "fr"),
            ],
        )

if __name__ == "__main__":
    init_db()
    print("Database initialized")
</code></pre>



<p>Note that we directly save the hashed password in the <code>users</code> table.</p>



<p>Then, we simply query this database in our <code>auth_func</code> function to get the hashed password of a user, then compare it:</p>



<pre class="wp-block-code"><code lang="python" class="language-python">from dash import Dash, html
from dash_auth import BasicAuth
from werkzeug.security import generate_password_hash, check_password_hash
import sqlite3

DB_PATH = "users.db"

def get_hash(username):
    """Fetch the stored hash for a username, or None."""
    with sqlite3.connect(DB_PATH) as con:
        cur = con.cursor()
        cur.execute("SELECT password_hash FROM users WHERE username = ?", (username,))
        row = cur.fetchone()
        return row[0] if row else None

def auth_func(username, password):
    """ Authenticate the user using hashed passwords. """
    hash_from_db = get_hash(username)

    if hash_from_db and check_password_hash(hash_from_db, password):
        return True
    return False

app = Dash(__name__)
auth = BasicAuth(
    app, 
    auth_func=auth_func,
    secret_key="something_like_nUGz8DZvb..."
)

app.layout = html.Div([
    html.H1("Protected app"),
    html.P("If you see this, you are authenticated <img src="https://s.w.org/images/core/emoji/17.0.2/72x72/2705.png" alt="✅" class="wp-smiley" style="height: 1em; max-height: 1em;" />"),
])

if __name__ == "__main__":
    app.run(debug=True)
</code></pre>



<p>That&#8217;s it!</p>



<p>Now you can modify the list of users, modify passwords, etc. in the database without having to reload the application. <img src="https://s.w.org/images/core/emoji/17.0.2/72x72/1f642.png" alt="🙂" class="wp-smiley" style="height: 1em; max-height: 1em;" /></p>



<p>It doesn’t need to be a <code>sqlite</code> database. You can also make HTTP requests to a database provider, or query any other type of database (Postgresql, MongoDB, &#8230;).</p>



<p class="callout">Keep in mind that the <code>auth_func</code> function is executed for every callback and every dash request. If the check takes too much time, think about caching solutions like <code>memoize</code>.</p>



<h2 id='why-you-can-t-logout'  id="boomdevs_6" class="wp-block-heading" >Why you can’t logout</h2>



<p><code>dash-auth</code> uses <strong>HTTP Basic Authentication</strong>, which is built into your browser.</p>



<ul class="wp-block-list">
<li>Your credentials (username + password) are cached.</li>



<li>The browser automatically re-sends them with every request.</li>



<li>There’s no “logout” button because the browser doesn’t expose a way to clear those credentials.</li>
</ul>



<p>The only way to log out? Close the browser tab or window.</p>



<h2 id='conclusion'  id="boomdevs_7" class="wp-block-heading" >Conclusion</h2>



<p>This tutorial helped you to secure a Dash app using the <code>dash_auth</code> package. </p>



<p><code>dash-auth</code> has its drawbacks, but it’s a fairly easy solution to add an authentication layer to a dashboard or a data app. <img src="https://s.w.org/images/core/emoji/17.0.2/72x72/1f642.png" alt="🙂" class="wp-smiley" style="height: 1em; max-height: 1em;" /> However, I would not recommend using it for production apps that have very sensitive data. </p>



<p>If you need proper login/logout behavior (e.g., session expiration, multiple users switching), you’ll need a more advanced system such as:</p>



<ul class="wp-block-list">
<li><code>flask_login</code></li>



<li>OAuth (Google, GitHub…)</li>



<li>Enterprise identity providers (Okta, Auth0, Azure AD, …)</li>



<li><a href="https://plotly.com/dash/authentication/">Dash-Enterprise</a> (handles LDAP, SAML, OIDC)</li>
</ul>



<p>In the next tutorial, we will see <a href="https://dash-resources.com/how-to-secure-a-multi-page-dash-app-with-dash-auth/">how to use <code>dash-auth</code> for multi-pages Dash apps.</a></p>



<p>I hope to see you there!</p>



<p></p>
<p>L’article <a href="https://dash-resources.com/how-to-secure-your-dash-app-with-dash-auth/">How to secure a Dash app with dash-auth</a> est apparu en premier sur <a href="https://dash-resources.com">dash-resources.com</a>.</p>
]]></content:encoded>
					
		
		
			</item>
	</channel>
</rss>
