A secure authentication module to manage user access in a Streamlit application
Streamlit-Authenticator is distributed via PyPI:
pip install streamlit-authenticator
Using Streamlit-Authenticator is as simple as importing the module and calling it to verify your user's credentials.
import streamlit as st
import streamlit_authenticator as stauth
cookie:
expiry_days: 30
key: some_signature_key # Must be a string
name: some_cookie_name
credentials:
usernames:
jsmith:
email: jsmith@gmail.com
failed_login_attempts: 0 # Will be managed automatically
first_name: John
last_name: Smith
logged_in: False # Will be managed automatically
password: abc # Will be hashed automatically
roles: # Optional
- admin
- editor
- viewer
rbriggs:
email: rbriggs@gmail.com
failed_login_attempts: 0 # Will be managed automatically
first_name: Rebecca
last_name: Briggs
logged_in: False # Will be managed automatically
password: def # Will be hashed automatically
roles: # Optional
- viewer
oauth2: # Optional
google: # Follow instructions: https://developers.google.com/identity/protocols/oauth2
client_id: # To be filled
client_secret: # To be filled
redirect_uri: # URL to redirect to after OAuth2 authentication
microsoft: # Follow instructions: https://learn.microsoft.com/en-us/graph/auth-register-app-v2
client_id: # To be filled
client_secret: # To be filled
redirect_uri: # URL to redirect to after OAuth2 authentication
tenant_id: # To be filled
pre-authorized: # Optional
emails:
- melsby@gmail.com
import yaml
from yaml.loader import SafeLoader
with open('../config.yaml') as file:
config = yaml.load(file, Loader=SafeLoader)
# Pre-hashing all plain text passwords once
# stauth.Hasher.hash_passwords(config['credentials'])
authenticator = stauth.Authenticate(
config['credentials'],
config['cookie']['name'],
config['cookie']['key'],
config['cookie']['expiry_days']
)
Hasher.hash_passwords
Parameters:
- credentials: dict
- The credentials dict with plain text passwords.
Returns:
- dict
- The credentials dict with hashed passwords.
Authenticate
Parameters:
- credentials: dict, str
- Dictionary with the usernames, names, passwords, and emails, and other user data, or path pointing to the location of the config file.
- cookie_name: str
- Specifies the name of the re-authentication cookie stored on the client's browser for password-less re-authentication.
- cookie_key: str
- Specifies the key that will be used to hash the signature of the re-authentication cookie.
- cookie_expiry_days: float, default 30.0
- Specifies the number of days before the re-authentication cookie automatically expires on the client's browser.
- validator: Validator, optional, default None
- Provides a validator object that will check the validity of the username, name, and email fields.
- auto_hash: bool, default True
- Automatic hashing requirement for passwords, True: plain text passwords will be hashed automatically, False: plain text passwords will not be hashed automatically.
- **kwargs: dict, optional
- Arguments to pass to the Authenticate class.
try:
authenticator.login()
except Exception as e:
st.error(e)
Authenticate.login
Parameters:
- location: str, {'main', 'sidebar', 'unrendered'}, default 'main'
- Specifies the location of the login widget.
- max_concurrent_users: int, optional, default None
- Limits the number of concurrent users. If not specified there will be no limit to the number of concurrently logged in users.
- max_login_attempts: int, optional, default None
- Limits the number of failed login attempts. If not specified there will be no limit to the number of failed login attempts.
- fields: dict, optional, default {'Form name':'Login', 'Username':'Username', 'Password':'Password', 'Login':'Login', 'Captcha':'Captcha'}
- Customizes the text of headers, buttons and other fields.
- captcha: bool, default False
- Specifies the captcha requirement for the login widget, True: captcha required, False: captcha removed.
- single_session: bool, default False
- Disables the ability for the same user to log in multiple sessions, True: single session allowed, False: multiple sessions allowed.
- clear_on_submit: bool, default False
- Specifies the clear on submit setting, True: clears inputs on submit, False: keeps inputs on submit.
- key: str, default 'Login'
- Unique key provided to widget to avoid duplicate WidgetID errors.
- callback: callable, optional, default None
- Callback function that will be invoked on form submission with a dict as a parameter.
try:
authenticator.experimental_guest_login('Login with Google',
provider='google',
oauth2=config['oauth2'])
authenticator.experimental_guest_login('Login with Microsoft',
provider='microsoft',
oauth2=config['oauth2'])
except Exception as e:
st.error(e)
Authenticate.experimental_guest_login
Parameters:
- button_name: str, default 'Guest login'
- Rendered name of the guest login button.
- location: str, {'main', 'sidebar'}, default 'main'
- Specifies the location of the guest login button.
- provider: str, {'google', 'microsoft'}, default 'google'
- Selection for OAuth2 provider, Google or Microsoft.
- oauth2: dict, optional, default None
- Configuration parameters to implement an OAuth2 authentication.
- max_concurrent_users: int, optional, default None
- Limits the number of concurrent users. If not specified there will be no limit to the number of concurrently logged in users.
- single_session: bool, default False
- Disables the ability for the same user to log in multiple sessions, True: single session allowed, False: multiple sessions allowed.
- roles: list, optional, default None
- User roles for guest users.
- callback: callable, optional, default None
- Callback function that will be invoked on button press with a dict as a parameter.
if st.session_state['authentication_status']:
authenticator.logout()
st.write(f'Welcome *{st.session_state["name"]}*')
st.title('Some content')
elif st.session_state['authentication_status'] is False:
st.error('Username/password is incorrect')
elif st.session_state['authentication_status'] is None:
st.warning('Please enter your username and password')
Authenticate.logout
Parameters:
- button_name: str, default 'Logout'
- Customizes the button name.
- location: str, {'main', 'sidebar', 'unrendered'}, default 'main'
- Specifies the location of the logout button. If 'unrendered' is passed, the logout logic will be executed without rendering the button.
- key: str, default None
- Unique key that should be used in multi-page applications.
- callback: callable, optional, default None
- Callback function that will be invoked on form submission with a dict as a parameter.
if st.session_state['authentication_status']:
try:
if authenticator.reset_password(st.session_state['username']):
st.success('Password modified successfully')
except Exception as e:
st.error(e)
Authenticate.reset_password
Parameters:
- username: str
- Specifies the username of the user to reset the password for.
- location: str, {'main', 'sidebar'}, default 'main'
- Specifies the location of the reset password widget.
- fields: dict, optional, default {'Form name':'Reset password', 'Current password':'Current password', 'New password':'New password', 'Repeat password': 'Repeat password', 'Reset':'Reset'}
- Customizes the text of headers, buttons and other fields.
- clear_on_submit: bool, default False
- Specifies the clear on submit setting, True: clears inputs on submit, False: keeps inputs on submit.
- key: str, default 'Reset password'
- Unique key provided to widget to avoid duplicate WidgetID errors.
- callback: callable, optional, default None
- Callback function that will be invoked on form submission with a dict as a parameter.
Returns::
- bool
- Status of resetting the password.
try:
email_of_registered_user, \
username_of_registered_user, \
name_of_registered_user = authenticator.register_user(pre_authorized=config['pre-authorized']['emails'])
if email_of_registered_user:
st.success('User registered successfully')
except Exception as e:
st.error(e)
Authenticate.register_user
Parameters:
- location: str, {'main', 'sidebar'}, default 'main'
- Specifies the location of the register user widget.
- pre_authorized: list, optional, default None
- List of emails of unregistered users who are authorized to register. If no list is provided, all users will be allowed to register.
- domains: list, optional, default None
- Specifies the required list of domains a new email must belong to i.e. ['gmail.com', 'yahoo.com'], list: the required list of domains, None: any domain is allowed.
- fields: dict, optional, default {'Form name':'Register user', 'Email':'Email', 'Username':'Username', 'Password':'Password', 'Repeat password':'Repeat password', 'Password hint':'Password hint', 'Captcha':'Captcha', 'Register':'Register'}
- Customizes the text of headers, buttons and other fields.
- captcha: bool, default True
- Specifies the captcha requirement for the register user widget, True: captcha required, False: captcha removed.
- roles: list, optional, default None
- User roles for registered users.
- merge_username_email: bool, default False
- Merges username into email field, True: username will be the same as the email, False: username and email will be independent.
- clear_on_submit: bool, default False
- Specifies the clear on submit setting, True: clears inputs on submit, False: keeps inputs on submit.
- key: str, default 'Register user'
- Unique key provided to widget to avoid duplicate WidgetID errors.
- callback: callable, optional, default None
- Callback function that will be invoked on form submission with a dict as a parameter.
Returns:
- str
- Email associated with the new user.
- str
- Username associated with the new user.
- str
- Name associated with the new user.
try:
username_of_forgotten_password, \
email_of_forgotten_password, \
new_random_password = authenticator.forgot_password()
if username_of_forgotten_password:
st.success('New password to be sent securely')
# The developer should securely transfer the new password to the user.
elif username_of_forgotten_password == False:
st.error('Username not found')
except Exception as e:
st.error(e)
Authenticate.forgot_password
Parameters
- location: str, {'main', 'sidebar'}, default 'main'
- Specifies the location of the forgot password widget.
- fields: dict, optional, default {'Form name':'Forgot password', 'Username':'Username', 'Captcha':'Captcha', 'Submit':'Submit'}
- Customizes the text of headers, buttons and other fields.
- captcha: bool, default False
- Specifies the captcha requirement for the forgot password widget, True: captcha required, False: captcha removed.
- clear_on_submit: bool, default False
- Specifies the clear on submit setting, True: clears inputs on submit, False: keeps inputs on submit.
- key: str, default 'Forgot password'
- Unique key provided to widget to avoid duplicate WidgetID errors.
- callback: callable, optional, default None
- Callback function that will be invoked on form submission with a dict as a parameter.
Returns:
- str
- Username associated with the forgotten password.
- str
- Email associated with the forgotten password.
- str
- New plain text password that should be transferred to the user securely.
try:
username_of_forgotten_username, \
email_of_forgotten_username = authenticator.forgot_username()
if username_of_forgotten_username:
st.success('Username to be sent securely')
# The developer should securely transfer the username to the user.
elif username_of_forgotten_username == False:
st.error('Email not found')
except Exception as e:
st.error(e)
Authenticate.forgot_username
Parameters
- location: str, {'main', 'sidebar'}, default 'main'
- Specifies the location of the forgot username widget.
- fields: dict, optional, default {'Form name':'Forgot username', 'Email':'Email', 'Captcha':'Captcha', 'Submit':'Submit'}
- Customizes the text of headers, buttons and other fields.
- captcha: bool, default False
- Specifies the captcha requirement for the forgot username widget, True: captcha required, False: captcha removed.
- clear_on_submit: bool, default False
- Specifies the clear on submit setting, True: clears inputs on submit, False: keeps inputs on submit.
- key: str, default 'Forgot username'
- Unique key provided to widget to avoid duplicate WidgetID errors.
- callback: callable, optional, default None
- Callback function that will be invoked on form submission with a dict as a parameter.
Returns:
- str
- Forgotten username that should be transferred to the user securely.
- str
- Email associated with the forgotten username.
if st.session_state['authentication_status']:
try:
if authenticator.update_user_details(st.session_state['username']):
st.success('Entries updated successfully')
except Exception as e:
st.error(e)
Authenticate.update_user_details
Parameters
- username: str
- Specifies the username of the user to update user details for.
- location: str, {'main', 'sidebar'}, default 'main'
- Specifies the location of the update user details widget.
- fields: dict, optional, default {'Form name':'Update user details', 'Field':'Field', 'First name':'First name', 'Last name':'Last name', 'Email':'Email', 'New value':'New value', 'Update':'Update'}
- Customizes the text of headers, buttons and other fields.
- clear_on_submit: bool, default False
- Specifies the clear on submit setting, True: clears inputs on submit, False: keeps inputs on submit.
- key: str, default 'Update user details'
- Unique key provided to widget to avoid duplicate WidgetID errors.
- callback: callable, optional, default None
- Callback function that will be invoked on form submission with a dict as a parameter.
Returns:
- bool
- Status of updating the user details.
with open('../config.yaml', 'w') as file:
yaml.dump(config, file, default_flow_style=False)
This project is proprietary software. The use of this software is governed by the terms specified in the LICENSE file. Unauthorized copying, modification, or distribution of this software is prohibited.