mkhorasani / Streamlit-Authenticator

A secure authentication module to manage user access in a Streamlit application.
Other
1.53k stars 246 forks source link

Authentication status reverts back to True after successful logout and page refresh. #203

Open arishokri opened 2 weeks ago

arishokri commented 2 weeks ago

So I'm not sure why this is happening. But with having cookies active, even after use successfully logs out, a page refresh changes the authentication status back to True effectively kicks the user back into logged in status without authentication required. This always happens with the first successful logout attempt but if the user refreshes the page, and logs out one more time the problem resolves itself. Also, changing cookies name of key temporarily resolves the problem.

Client: Chrome on Mac, Version 127.0.6533.120 (Official Build) (arm64) Server1: Nginx on Ubuntu Server2: Macbook with M3 Pro

Code related to authentication:

import streamlit as st
import streamlit_authenticator as stauth
import yaml
from yaml.loader import SafeLoader
from yaml.dumper import SafeDumper
from streamlit import session_state as ss

# Loads the authenticator config file and saves authenticator parameters to session_sate.
# Saves authenticator object to session_sate.
def load_auth_creds() -> None:
    with open(".streamlit/authentication.yaml", "r") as file:
        auth_config = yaml.load(file, Loader=SafeLoader)
    authenticator = stauth.Authenticate(
        auth_config["credentials"],
        auth_config["cookie"]["name"],
        auth_config["cookie"]["key"],
        auth_config["cookie"]["expiry_days"],
        auth_config["preauthorized"],
    )
    ss.auth_config = auth_config
    ss.authenticator = authenticator

# Updates user credentials to the authentication config file.
def rewrite_auth_creds() -> None:
    with open(".streamlit/authentication.yaml", "w") as file:
        yaml.dump(ss.auth_config, file, default_flow_style=False, Dumper=SafeDumper)

# Sets up the initial user authentication.
# And saves the autherized status and parameters to the session state.
def init_authenticate() -> None:
    load_auth_creds()
    try:
        # The login method automatically sets session_sate variables name, authentication_status, and username
        # to their respective values after successfull authentication.
        ss.authenticator.login(key="login", location="main", captcha=True)
    except Exception as e:
        st.error(e)
    if ss.authentication_status is not None: # Rewrite authentication file upon success or failure.
        rewrite_auth_creds()

# Provides a dialog with a function that logs the user out
# and rewrites the logged_in status in authentication config file
@st.dialog("Are you sure you want to log out?")
def logout_dialog() -> None:
    ss.authenticator.logout(key="logout_key")
    if ss.logout_key:
        rewrite_auth_creds()
        st.rerun()

init_authenticate()

if ss.authentication_status:
st.markdown(f"User: **{ss.name}**")
st.button(label="Logout", on_click=logout_dialog)
render_pages() # To render rest of the app...
mkhorasani commented 2 weeks ago

@bongton if you want to share source code please point to an existing repo on GitHub, don't share external files.

chuong98 commented 2 weeks ago

@arishokri I have the same issue, I fixed the issue by render a button Logout. See the following snippet code:

from streamlit import session_state as ss
auth = Authenticate(
        config['credentials'],
        config['cookie']['name'],
        config['cookie']['key'],
        config['cookie']['expiry_days'],
        config['pre-authorized'],
        auto_hash=True
    )
 if ss.authentication_status:
    st.subheader(f"Welcome {ss.username}! You are logged in.", divider='rainbow')
    with st.sidebar:
        if st.button(label="Logout", use_container_width=True,type='primary'):
            ss['WhoAmI']=ss.guest
            auth.logout()
            ss.authentication_status=None
            st.rerun()