mkhorasani / Streamlit-Authenticator

A secure authentication module to validate user credentials in a Streamlit application.
Apache License 2.0
1.38k stars 229 forks source link

Cannot use authenticate with multipage app #76

Closed johnnyb1509 closed 7 months ago

johnnyb1509 commented 11 months ago

Hi,

I have a problem when using authentication process for multiple app. Specifically the directory tree as below

Homepage.py
pages/
------- Page1.py
------- Page1_1.py
------- Page1_2.py
------- Page2.py

In which, inside the Homepage.py, I'm using these code

from streamlit_extras.switch_page_button import switch_page
import streamlit_authenticator as stauth
import yaml
from yaml.loader import SafeLoader
with open('settings/configAuth.yaml') as file:
    config = yaml.load(file, Loader=SafeLoader)

authenticator = stauth.Authenticate(
    config['credentials'],
    config['cookie']['name'],
    config['cookie']['key'],
    config['cookie']['expiry_days']
)

name, authentication_status, username = authenticator.login('Login', 'main')

if authentication_status:
    authenticator.logout('Logout', 'main', key='unique_key')
    if 'authentication_status' not in st.session_state:
        st.session_state["authentication_status"] = True #set the state with key
    st.write(f'Welcome *{name}*')
    #============================================================
    switch_page("Page1")
elif authentication_status is False:
    st.error('Username/password is incorrect')
elif authentication_status is None:
    st.warning('Please enter your username and password')

My Page1.py code is as below:

if st.session_state["authentication_status"]:
 >>> Do something and functions to switch to other pages in pages directory
elif st.session_state["authentication_status"] is False:
    st.error('Username/password is incorrect')
elif st.session_state["authentication_status"] is None:
    st.warning('Access Denied, please login')

At the first stage, the code works properly when standing at Homepage and it switchs directly to Page1 if username/password invalid.

From Page1, there have function to switch to other pages. And the problem occurs when I came to Page1_1 or others pages, then go back to Page1, at this time it raise an error as below

KeyError: 'st.session_state has no key "authentication_status". Did you forget to initialize it? More info: https://docs.streamlit.io/library/advanced-features/session-state#initialization'

How to solve this problem? And how to maintain the state of authenticate for every pages

NeyoxDrago commented 11 months ago

I was too facing the same issue, what solution i got is, we need to use that if condition snippets in every page, as the first time we do authentication, the browser cookies will get updated, hence whenever the same code is running in other pages , it reads that authentication is already done and reads the other details of the logged in user.

joydisette commented 10 months ago

I am not sure if it's the best solution but I use st.session_state to keep track of authentication status. Basically on my Welcome page i have this:

if authentication_status:
    authenticator.logout('Logout', 'sidebar', key='unique_key')
    st.session_state['user_authenticated'] = True

then on all other pages I have this condition that checks if user is authenticated, and if not it stops exectution and prints a warning for the user to go back to welcome page and login:

if not st.session_state['user_authenticated']:
    st.warning('Please login on the welcome page')
    st.stop()

Hope it helps!

mkhorasani commented 3 months ago

Dear all, if you are using Streamlit-Authenticator with multi-page apps, you will have to recreate the authenticator object on each and every page and invoke the login method as shown below:

authenticator = stauth.Authenticate(
    config['credentials'],
    config['cookie']['name'],
    config['cookie']['key'],
    config['cookie']['expiry_days'],
    config['pre-authorized']
)

authenticator.login()

This is to ensure that when a user hard refreshes the page and the session state variables related to re-authentication are lost, the authenticator object is there to re-initialize them from the cookie saved on the browser.