Multi Page App sometimes shows wrong page when deployed to server

Apologies in advance for not being able to share a lot of code. This app is considered IP for the company I work for and is not reproducible if ran locally.

I have a multi-page app that is deployed via Docker and ECS. Locally all pages work flawlessly, but when its deployed and multiple users are accessing the app, sometimes the logic to return a layout is wrong

When a user accesses the app, I capture JWTs through Okta to use for page authentication. If a user is not in a certain group and try to access an unauthorized page, a not_authorized layout is returned.

I store the user’s data with dcc.store for the session in my app.py and refer to in every page.

Below is the code on what layout to return. The layout variable is based on what page the user clicks on in the NavBar.

    if len(not_auth_roles) > 0:
        return dash.page_registry["modules.not_authorized"]["layout"]
    elif layout == "":
        return dash.page_registry["modules.not_found"]["layout"]
    else:
        return dash.page_registry[f"modules.{layout}"]["layout"]

Anyone else run into a similar issue?

Hello @Zak,

Depending on the store type, switching between levels will not work as well because a store will only push data if it is done via a callback if it already exists.

This is what allows for recalling and apps state.

If you need to store the status in something, you can always use a session cookie, just give it a good passkey to secure it and make sure it is http only and secure. Also make sure you don’t store critical info in the cookie.

Flask session cookies are able to be used in all requests and callbacks, barring the background callback which takes some outside the box thinking.

If you want to stick with the store, have a callback that will delete the store from the app, this should allow you to reset the navigation etc.

I personally wouldn’t use a store, as if bad actors were to figure this out, they could manipulate and gain access to your site. :grin:

Thanks for the reply, I am storing it for just the session. Once its stored, its does not need to be updated again.

I should clarify, the data being stored is not sensitive in nature. It is pulling the user’s Active Directory groups and checking if they are in the correct one to access a particular page. When the app initially runs, I have a callback that the data that is then referenced other places in the app.

app.layout = html.Div(
    [
        dcc.Store(id="session_data", data=dict(), storage_type="session"),
       ...
   ]
)

@app.callback(
    Output(component_id="session_data", component_property="data"),
    [Input(component_id="session_data", component_property="data")],
)
def user_info_session(session_data):
    session_data["user_info"] = get_user_info() # get user ID, etc.
    session_data["user_roles"] = get_user_roles(session_data, config) # get user AD groups
    return session_data

I am open to changing how this is handled, but this issue has been hard to debug since it only happens when multiple users are accessing the app. From a high level, it looks like the stored data is getting mixed up between users, but that shouldn’t happen, right? Do I need to add more workers,? Right now it is just being ran on 2 containers without gunicorn.

This shouldn’t be an issue.

It’s not about storing sensitive data, but being able to gain access to sensitive data. Which if manipulating a store a low level user could gain access to admins functions by manipulating the store. That’d be bad.

Do you have people switching from one user to another user on the same machine? If so, that could be your problem.

Also, without seeing what your functions are, it’s impossible to tell if that not where you are getting things crisscrossed.

Or if you are using flask caching of functions, that could be an issue.

Fair point, I will look at alternatives.

Users are on separate machines, and I am not using flask caching functions either.

I wish I could share more of my code, but I cannot. I will keep troubleshooting to see if I can come up with a solution. If I have time, I will try to recreate without any company info.

Do you have any global variables?

No global variables!

Unfortunately, without seeing more of your code, I’m not sure there is much else to offer in the way of helping. :pensive: