Integrating authentication for Dash in a multi-page scenario

I am trying to integrate authentication in a Dash multi-page application. I have got the Azue AD authentication to work for a Flask application. I have extended the concept, by using the before_request approach shown in the snippets further below. Just wanted to check with the community if there is something better

Current setup

I have Flask-Azure AD configured as per MS guidance and the authentication works very well with Flask views.

/login view

@app.route("/login")
def login():
    auth_url = msal_app.get_authorization_request_url(
        SCOPE, redirect_uri=url_for("authorized", _external=True)
    )
    return redirect(auth_url)

Multi-page folder structure

image

Example of page1

import os
import logging
from datetime import datetime
import dash
from dash import html

dash.register_page(__name__, title=f'Page1 ({os.environ.get("ENVIRONMENT")})')


def layout():
    logging.info('Page handler:{__name__}')
    html_elements = html.Div([
        html.H1('This is Page1'),
        html.Div(f'This is our Page1 content. {datetime.now()}'),
    ])
    return html_elements

Multi-page Dash registration

with app.app_context():
    logging.info("Inside app_context")
    dash_app = dash.Dash(use_pages=True, server=app,
                         prevent_initial_callbacks=True,
                         url_base_pathname="/dash/")

before_request handler

I am checking if the URL begins with dash and if session is missing, then re-route to the login view

@app.before_request
def before_app_request():
    current_path = request.path
    current_url = request.url
    logging.info(f"Before request: Path = {current_path}, URL = {current_url}")
    if not current_path.startswith("/dash/"):
        return
    if not session.get("user"):
        logging.info("User not authenticated, redirecting to login")
        return redirect(url_for("login"))
    else:
        logging.info(f"User authenticated: {session['user']['name']}")

Question

  • It gives me a central function to introspect the URL.
  • I do not need to code in the respetive layout callback functions

While, the above approach works is there anything better ?

Thanks,
Sau

Authentication is a pain to setup :tired_face: honestly the easiest approach would be to use dash enterprise if you wanna retain your sanity.

I recently got social cross application authentication working. And it took me a bit over a year of back and forth trying new approaches till i found something that worked.

I can’t give you my secret sauce but I can give you some tips / tricks to help you along this process.

Tips:

  • Use logging & setup a pipeline that automatically deploys your application and use a grafana server to see the logs in production. A pain to setup but it will pay dividend.
  • depending on if you are using a proxy to host I used ProxyFix which treated me well.
  • I went with flask sessions and cookies something like:
server.config['SESSION_PERMANENT'] = True
server.config['PERMANENT_SESSION_LIFETIME'] = timedelta(days=7) # Session lifetime
server.config['SESSION_COOKIE_SECURE'] = is_production # True in production (HTTPS required)
server.config['SESSION_COOKIE_HTTPONLY'] = True
server.config['SESSION_COOKIE_SAMESITE'] = 'Lax' # Good default
server.config['SESSION_FILE_DIR'] = session_dir # Directory for session files
server.config['SESSION_USE_SIGNER'] = True # Sign the session cookie id

Session(server)
  • You are on the right path with app.before_request but my before_app_request contains substantially more logic
  • I use auth-store which is just a dcc.Store for my callbacks to easily retrieve authentication information
  • Browser console → Application → cookies , is your best friend use it to check what cookies are being saved in regards to authentication
  • depending on the path you are doing you might want a templates/index.html page and you might want to use custom .js to help guide parts of the authentication system
  • I use azure key vault to retrieve secrets from my github secrets manager and an action within the pipeline to retrieve and setup all the important authentication variables securely
  • if you are looking to create a public facing application setting up a social authentication system usually increases the sign up rate for apps by 20%-60% more than a basic username and password

You can test out my authentication system if you’d like inspiration:
authentication_example

If you login to that application it automatically continues into other applications I host like:

Wish i could give more direct information on how to set this up but its very dependent on app, developer, host system, stack and authentication being used. Most authentication systems are not identical… but all authentication systems should be secure :sweat_smile:

Hope this helps,
pip

1 Like