GithubHelp home page GithubHelp logo

mkhorasani / streamlit-authenticator Goto Github PK

View Code? Open in Web Editor NEW
1.2K 15.0 211.0 711 KB

A secure authentication module to validate user credentials in a Streamlit application.

License: Apache License 2.0

Python 100.00%
authentication python streamlit streamlit-component

streamlit-authenticator's Introduction

Streamlit Authenticator logo

A secure authentication module to validate user credentials in a Streamlit application

Downloads Downloads Downloads


To learn more please refer to my book Web Application Development with Streamlit.

Installation

Streamlit-Authenticator is distributed via PyPI:

pip install streamlit-authenticator

Example

Using Streamlit-Authenticator is as simple as importing the module and calling it to verify your predefined users' credentials.

import streamlit as st
import streamlit_authenticator as stauth

1. Creating a configuration file

  • Initially create a YAML configuration file and define your user's credentials: including names, usernames, and passwords (plain text passwords will be hashed automatically).
  • In addition, enter a name, random key, and number of days to expiry for a re-authentication cookie that will be stored on the client's browser to enable password-less re-authentication. If you do not require re-authentication, you may set the number of days to expiry to 0.
  • Finally, define a list of pre-authorized emails of users who can register and add their credentials to the configuration file with the use of the register_user widget.
  • Please remember to update the config file (as shown in step 9) after you use the reset_password, register_user, forgot_password, or update_user_details widgets.
credentials:
  usernames:
    jsmith:
      email: jsmith@gmail.com
      failed_login_attempts: 0 # Will be managed automatically
      logged_in: False # Will be managed automatically
      name: John Smith
      password: abc # Will be hashed automatically
    rbriggs:
      email: rbriggs@gmail.com
      failed_login_attempts: 0 # Will be managed automatically
      logged_in: False # Will be managed automatically
      name: Rebecca Briggs
      password: def # Will be hashed automatically
cookie:
  expiry_days: 30
  key: some_signature_key # Must be string
  name: some_cookie_name
pre-authorized:
  emails:
  - melsby@gmail.com

Please note that the 'logged_in' field corresponding to each user's log-in status will be added automatically.

2. Creating a login widget

  • Subsequently import the configuration file into your script and create an authentication object.
  • Please remember to recreate the authenticator object on each and every page in a multi-page application.
import yaml
from yaml.loader import SafeLoader

with open('../config.yaml') as file:
    config = yaml.load(file, Loader=SafeLoader)

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

Authenticate

Parameters:

  • credentials: dict
    • Provides the usernames, names, passwords, and emails, and other user data.
  • 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.
  • pre-authorized: list, default None
    • Provides the list of emails of unregistered users who are authorized to register.
  • validator: object, default None
    • Provides a validator object that will check the validity of the username, name, and email fields.
  • Then render the login module as follows.
  • Please remember to re-invoke the login function on each and every page in a multi-page application.
authenticator.login()

Authenticate.login

Parameters:

  • location: str, {'main', 'sidebar'}, default 'main'
    • Specifies the location of the login widget.
  • max_concurrent_users: int, default None
    • Limits the number of concurrent users. If not specified there will be no limit to the number of users.
  • max_login_attempts: int, 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, default {'Form name':'Login', 'Username':'Username', 'Password':'Password', 'Login':'Login'}
    • 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.

Returns:

  • str
    • Name of the authenticated user.
  • bool
    • Status of authentication, None: no credentials entered, False: incorrect credentials, True: correct credentials.
  • str
    • Username of the authenticated user.

3. Authenticating users

  • You can then retrieve the name, authentication status, and username from Streamlit's session state using st.session_state["name"], st.session_state["authentication_status"], and st.session_state["username"] to allow a verified user to proceed to any restricted content.
  • You may also render a logout button, or may choose not to render the button if you only need to implement the logout logic programmatically.
  • The optional key parameter for the logout button should be used with multi-page applications to prevent Streamlit from throwing duplicate key errors.
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.

  • Or prompt an unverified user to enter a correct username and password.

  • You may also retrieve the number of failed login attempts a user has made by accessing st.session_state['failed_login_attempts'] which returns a dictionary with the username as key and the number of failed attempts as the value.

4. Creating a reset password widget

  • You may use the reset_password widget to allow a logged in user to modify their password as shown below.
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, 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.

Returns::

  • bool
    • Status of resetting the password.

Please remember to update the config file (as shown in step 9) after you use this widget.

5. Creating a new user registration widget

  • You may use the register_user widget to allow a user to sign up to your application as shown below. If you require the user to be pre-authorized, set the pre-authorization argument to True and add their email to the pre-authorized list in the configuration file. Once they have registered, their email will be automatically removed from the pre-authorized list in the configuration file. Alternatively, to allow anyone to sign up, set the pre-authorization argument to False.
try:
    email_of_registered_user, username_of_registered_user, name_of_registered_user = authenticator.register_user(pre_authorization=False)
    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-authorization: bool, default True
    • Specifies the pre-authorization requirement, True: user must be pre-authorized to register, False: any user can register.
  • domains: list, 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, default {'Form name':'Register user', 'Email':'Email', 'Username':'Username', 'Password':'Password', 'Repeat password':'Repeat password', 'Register':'Register'}
    • 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.

Returns:

  • str
    • Email associated with the new user.
  • str
    • Username associated with the new user.
  • str
    • Name associated with the new user.

Please remember to update the config file (as shown in step 9) after you use this widget.

6. Creating a forgot password widget

  • You may use the forgot_password widget to allow a user to generate a new random password. This password will be automatically hashed and saved in the configuration file. The widget will return the username, email, and new random password which the developer should then transfer to the user securely.
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, default {'Form name':'Forgot password', 'Username':'Username', 'Submit':'Submit'}
    • 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.

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.

Please remember to update the config file (as shown in step 9) after you use this widget.

7. Creating a forgot username widget

  • You may use the forgot_username widget to allow a user to retrieve their forgotten username. The widget will return the username and email which the developer should then transfer 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, default {'Form name':'Forgot username', 'Email':'Email', 'Submit':'Submit'}
    • 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.

Returns:

  • str
    • Forgotten username that should be transferred to the user securely.
  • str
    • Email associated with the forgotten username.

8. Creating an update user details widget

  • You may use the update_user_details widget to allow a logged in user to update their name and/or email. The widget will automatically save the updated details in both the configuration file and re-authentication cookie.
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, default {'Form name':'Update user details', 'Field':'Field', 'Name':'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.

Returns:

  • bool
    • Status of updating the user details.

Please remember to update the config file (as shown in step 9) after you use this widget.

9. Updating the configuration file

  • Please ensure that the configuration file is re-saved anytime the credentials are updated or whenever the reset_password, register_user, forgot_password, or update_user_details widgets are used.
with open('../config.yaml', 'w') as file:
    yaml.dump(config, file, default_flow_style=False)

streamlit-authenticator's People

Contributors

mkhorasani avatar velicanu avatar vince-weka avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

streamlit-authenticator's Issues

NameError: name 'SafeLoader' is not defined

ymal config loader might depreciated? I try running the code and there's an error about "Loader=SafeLoader" I switch to new code below and found working.

with open('user.ymal') as file:
# config = yaml.load(file, Loader=SafeLoader) # previous code, not working
config = yaml.safe_load(file) # new code (working)

SNAG-0087

DuplicateWidgetID: There are multiple identical st.button widgets with the same generated key.

When following and try running code from github. Everything function except there's an error of streamlit.

My Analysis and solution: st.button widget required assigned "different" keyname and the backend code use the same keyname, resulting in an error.

error msg from cli:
'''
streamlit.errors.DuplicateWidgetID: There are multiple identical st.button widgets with the
same generated key.

When a widget is created, it's assigned an internal key based on
its structure. Multiple widgets with an identical structure will
result in the same internal key, which causes this error.

To fix this error, please pass a unique key argument to
st.button.
'''

SNAG-0086

login cache error

Hi,
i'm developing 2 different apps with 2 different sets of users.
App 1 works fine. App 2 shows the following error

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

With some trial and error, seems like the browser has the app 1 user list cached and apply's it to app 2, could it be?
Or is unrelated?
thanks

code to reproduce

def get_login():
    filename = 'app_users_config.yaml'
    with open(filename) as file:
        config = yaml.load(file, Loader=SafeLoader)
    authenticator = Authenticate(
        config['credentials'],
        config['cookie']['name'],
        config['cookie']['key'],
        config['cookie']['expiry_days'],
        config['preauthorized']
    )
    name, authentication_status, username = authenticator.login('Login', 'main')
    if authentication_status is None:
        st.warning('Please enter your username and password')
        login = False
    elif not authentication_status:
        st.error('Username/password is incorrect')
        login = False
    elif authentication_status:
        login = True
    else:
        raise ValueError(f"{authentication_status=}")
    return login, username

def app():
    st.title('test)
    login, username = get_login()
    if not login:
        return
    st.text('Running')

Customize "Username", "Password", "Login"

Hi @mkhorasani, thanks a lot for maintaining this awesome module! I'd like to be able to customize the labels for the two text_inputs and for the button. Specifically, I'd make them lower caps so that they fit in with the rest of the naming pattern in the screenshot below. I could do a PR myself, as I feel there are literally 4 lines of code to change. Let me know what you think!

# current
name, authentication_status = authenticator.login('login', 'sidebar')

# suggestion
name, authentication_status = authenticator.login('login', 'sidebar', 'username', 'password', 'login') # where the new ones have defaults

Edit: Same for "Logout" would be nice, too.

Screenshot from 2022-01-06 10-16-41

Logging users

I'm looking for a way to track the users login by writing a new line to a db table on each successful login.
Triggering the write after if authentication_status: will trigger everytime the app gets rerun, not just on login.

Is there a way to get just the "original" login?

Failure with cookie authentication patch required as workaround

I am using streamlit-Authenticator which works almost fine except that cookie faster reauthentication never worked.

I am using streamline 1.20.0 and streamlit-authenticator 0.2.1 with python 3.10.6

I've done some analysis and found that the problem is in the module streamlit_authenticator/authenticate.pyat line #106.

The function call :

self.token = self.cookie_manager.get(self.cookie_name)

do NOT return the token value but return None (I checked that the browser effectively sent the cookie properly).

I replaced this line by:

allCookies = self.cookie_manager.get_all()
self.token = allCookies.get(self.cookie_name, None)

and then the correct token value is recovered and processed as expected allowing me to recover authentication.

Any idea why the get do not work ?

Reuse username after login

Hi,

Do you know how it would be possible to reuse the username after the user logins? I want to pass it onto a query to search in a pandas dataframe so I can display information pertaining only to that user.

Thanks,

Implementing a "register user" fails

I've added a widget to allow user to register (per the doc):
try:
if authenticator.register_user('Register user', preauthorization=False):
st.success('User registered successfully')
except Exception as e:
st.error(e)

But when loading the app, I get:
"Pre-authorization argument must not be None"

streamlit == 1.9.2
streamlit-authenticator == 0.2.1
OS == Ubuntu 16.04
Python == 3.6.13

Screen Shot 2022-11-30 at 6 18 04 PM

Not able to create a new account using register_user

I am new to streamlit. I want to have a login and signup functionality in my application. I am able to successfully implement login using the username and password stored in the config.yaml file. However, I am not able to properly implement the register_user or reset/update the password. The program runs smoothly and I get the 'registration successful' message but when I try to log in using the new credentials I get the 'incorrect username/password' error.

image

image

Clean up README.md

Some possible corrections:

  1. Say somewhere one needs to install pyyaml and import yaml
  2. In the first code snippet in 'Creating a login widget', replace Loader=SafeLoader by Loader=yaml.SafeLoader

Or something like that as I struggled to realize the above from the README.md. It may be obvious to a lot of folks but it was not to me.

I could do it myself but I am hesitant as I don't want to interfere in your README. Package is great by the way! Thanks!

Extra-Streamlit-Components breaks Authenticator?

Had installed authenticator, everything set up and working fine, then decided to install extra components to take a look and now login for throws this error over and over. "Invalid Salt""

The only other things I can think that may have caused this was wiping the cache, but pretty confident I had done that already with no issues.

Any ideas for a fix?

Logout requires two presses

When using the log out button it always seems to require at least two presses to fully logout back to the login screen.

Code executed 3 times when login

Hello,
When you log in with Streamlit-Authenticator, the code is executed 3 times.
I added a print('test') command and I can see 'test' 3 times in the console.

I'm using version 0.2.1.

import streamlit as st
import streamlit_authenticator as stauth
import yaml

st.set_page_config(page_title='Auth', layout='wide')

# Load Authenticator Configuration
with open('config.yaml') as file:
    config = yaml.load(file, Loader=stauth.SafeLoader)

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

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

if st.session_state["authentication_status"]:
    authenticator.logout('Logout', 'main')
    st.write(f'Welcome *{st.session_state["name"]}*')
    st.title('Some content')
    print("test")
elif st.session_state["authentication_status"] == False:
    st.error('Username/password is incorrect')
elif st.session_state["authentication_status"] == None:
    st.warning('Please enter your username and password')

After logging in, the problem doesn't occur again.

Feature - Disallow registration if email is already taken.

Currently the registration only blocks registration if the username is already taken, but it allows to register with the same email infinite time, which is not good.
Perhaps you could add a feature that doesnt allow to use the same email more than once.

compatibility issue with chrome extension

Hi,

I found that if I enable the evernote clipper in the chrome, I can't login for some reason, and nothing is displayed in the terminal.

Other extension have nothing to do with the compatibility issue.

Would you please check it out?

st.button calling authenticator.forgot_username returns None and empty tuple

Still learning streamlit, so maybe a newbie question:
Following your README example, I create the streamlit_local_auth.py
As you can see from the code, I use a st.button to call forgot_username_button method.

def forgot_username_button(auth):
    try:
        username_forgot_username, email_forgot_username = auth.forgot_username('Find my username')

        if username_forgot_username:
            return st.success('Username sent securely')
            # Username to be transferred to user securely
        elif username_forgot_username == False:
            return st.error('Email not found')
        print(username_forgot_username, email_forgot_username)
    except Exception as e:
        return st.error(e)
    

if not authentication_status:
    if st.button("forgot username"):
        forgot_username_button(authenticator)

Unfortunately, it seems username_forgot_username, email_forgot_username returned from auth.forgot_username method are somehow None and ""(empty string). Even if I pass authenticator as a parameter!

Please help. Thx a lot!

Any way to enable enter key?

Hi,
I want to press the enter key on the keyboard for authentication instead of clicking the login button.
Any way to enable this function?

Custom fields in reg form

Good day. Is it possible to add additional (custom) fields to the registration form? I edited your code for my application, but it's the wrong way ))) It would be very nice to be able to add some number of input fields without having to fix the code arbitrarily manually.
Thank you for your job! Well done!

ValueError: Please enter hashed passwords... even though it is already hashed.

First of all, thanks for the awesome module. I get this error even though the password I used is hashed. I can login just fine on the second attempt though.

ValueError: Please enter hashed passwords and not plain text passwords into the 'authenticate' module.
Traceback:
File "/Users/server/opt/miniconda3/envs/parakeet/lib/python3.9/site-packages/streamlit/script_runner.py", line 379, in _run_script
    exec(code, module.__dict__)
File "/Users/server/Parakeet/main.py", line 64, in <module>
    main()
File "/Users/server/Parakeet/main.py", line 54, in main
    draw_sidebar()
File "/Users/server/Parakeet/main.py", line 41, in draw_sidebar
    name, authentication_status = authenticator.login('Login','sidebar')
File "/Users/server/opt/miniconda3/envs/parakeet/lib/python3.9/site-packages/streamlit_authenticator/__init__.py", line 188, in login
    raise ValueError("Please enter hashed passwords and not plain text passwords into the 'authenticate' module.")

Return user email, Name for new user

Hi,
Is there a way that we can get the email address and the name of the newly registered user without modifying the package code. Currently is returns if a new user has successfully created account or not.

auth with st.set_page_config

When i define code for authentication in my def main() in wihch st.set_page_config(layout="wide"). My app not working.
def main():
names = ['John Smith','Rebecca Briggs']
usernames = ['jsmith','rbriggs']
passwords = ['123','456']
hashed_passwords = stauth.Hasher(passwords).generate()
authenticator = stauth.Authenticate(names,usernames,hashed_passwords,
'some_cookie_name','some_signature_key',cookie_expiry_days=30)
name, authentication_status, username = authenticator.login('Login','main')

if authentication_status:
    current_plan = data.get_current_capacity_plan()
    setup_multipage(current_plan)
    refresher.start()
elif authentication_status == False:
    st.error('Username/password is incorrect')
elif authentication_status == None:
    st.warning('Please enter your username and password')

st.set_page_config(
    page_title='app_name',
    layout='wide',
) 

That in error trace
StreamlitAPIException: set_page_config() can only be called once per app, and must be called as the first Streamline command in your script.

when st.set_page_config is commented out everything works

ideas? i dont understand where st.set_page_config can called. Or how i can define default page config for authentication

Can I block a new login, when a user is already logged in?

Hello, I have a streamlit webapp that uses streamlit-authenticator and it works just fine, but we have seen some 'collisions' when two users are logged in a the same time (same variable names, different values, erase each other temporary files, and so on). Is there a way to block the new login to be sure that only one user can login at the same time?

option to disable hashing

Hi, thanks for creating this component! I find the cookie authentication very useful.

I am storing the config as a streamlit secret so it is not necessary to hash the passwords. Is it possible to disable this? Right now I am getting an invalid salt error when I try to use plain text passwords.

Example APP using streamlit-authenticator

Hi @mkhorasani,

Thank you for this amazing component!

It would be helpful if you created an example app using streamlit-authenticator so it is easier to quickstart using this component. I am having some issues using the component.

Best,
Ryan

Configuration file support for unicode

Congratulations on your great project.

I noticed an issue when the config.yaml contains unicode characters.
For example when using the reset password feature the yaml load and dump works perfectly but the process escapes all unicode chars. Unfortunately this cancels the yaml file human readability.

An simple solution would be to just use the allow_unicode parameter when dumping the config back to the filesystem:

with open('../config.yaml', 'w') as file:
yaml.dump(config, file, default_flow_style=False, allow_unicode=True, sort_keys=False)

How does it sound?
:)

Keep up the good work!

Feature - Only allow users within a certain domain to create an account

Small lift here. But it would be great if we could define who can create a user account. This would allow users to make a streamlit application public, and then allow everyone from their organization to create individual accounts.

Also happy to integrate this if you are willing to accept it :D

Constant authentication_status == False

hi , i was just working with streamlit-authenticator and was making a login page usng config.yaml , but it always outputing the authentication_status as False , however i have done exactly the same as there was in docs. Please help me to resolve this.
Also while deploying it on streamlit cloud, it was not getting the credentials from the repo .

The three-level credential dictionary is vey painful to use

Hi @mkhorasani , thank you for sharing this amazing package with us.
I found the new way of adding credentials very painful to use, especially for those who retrieve user information from a remote database.

  1. I don't think it's a good idea to create a three-level credential dictionary. It takes the users extra work to convert the data they retrieved from the database to the format that meets the requirement.
    As you can see below, the 'usernames' key in the dictionary is useless. Also, the keys at the second level of the dictionary are the usernames. The varying keys at this level make it a lot more difficult to do certain operations
    {'usernames': {'jsmith': {'email': '[email protected]', 'name': 'John Smith', 'password': 123}, 'rbriggs': {'email': '[email protected]', 'name': 'Rebecca Briggs', 'password': 456}}}
    Is there a specific reason for not using a much simpler structure like below?
    {'username': 'jsmith', 'email': '[email protected]', 'name': 'John Smith', 'password': 123}

  2. the Hashing passwords part also became very difficult to use. Previously, we only needed to provide a list of hashed passwords to the Authenticator. Now, we need to first retrieve the original passwords from the very painful 3-level dictionary and then hash them and then put them back. It feels like torture.

TypeError: __init__() got multiple values for argument 'cookie_expiry_days'

Hi,

We were able to use the following code with version 0.1.5 but after the update it started throwing this error. Please see the code below.

names = ['NAME']
usernames = ['USERNAME']
passwords = ['PASSWORD']

hashed_passwords = stauth.Hasher(passwords).generate()
authenticator = stauth.Authenticate(names,
                                    usernames,
                                    hashed_passwords,
                                    'some_cookie_name',
                                    'some_signature_key',
                                    cookie_expiry_days=30)

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

Case Sensitive Username

Amazing work on this module, thanks!!

It seems that the usernames are case sensitive.
As most users (that I know of) are not used to having case sensitive usernames, this will likely confuse them.

Is there any way to set the module to compare the username as case insensitive?

Newer version breaks with cookies from old version

Hi, I was using version 0.1.0, and when updated to version 0.1.4, because I and other users already have some cookies in the browsers, the code breaks when it tries to access the field username from the cookies.

The traceback is

File "/code/app/utils/misc.py", line 35, in authentication_workflow
    name, authentication_status, username = authenticator.login("Login", "sidebar")
File "/usr/local/lib/python3.8/site-packages/streamlit_authenticator/__init__.py", line 163, in login
    st.session_state['username'] = self.token['username']

Feature - Store YAML file in a remote data store

It would be terrific is the user credentials could be stored in a remote data store (Deta, Mongo, etc).

I would be happy to integrate this feature if you are interested in having it incorporated.

Automatically save and load hashed_passwords as a file

Hi,

First of all thank you for your work on Streamlit-Authenticator, it's a very appreciated module :)

I have a feature request to ease its use.
It turns out that once the hashed_passwords are generated with .Hasher.generate, I end up saving it as a txt file and then load it afterwards for the Authenticate method.

It would be easier to add the possibility to automatically save the hashed_passwords as a file (with the .generate method), and load it (with the .Authenticate method).

The workflow would look like this:

names = ['John Smith', 'Rebecca Briggs']
usernames = ['jsmith', 'rbriggs']
passwords = ['123', '456']

hashed_passwords = stauth.Hasher(passwords).generate(folder_path="path_to_folder")

A .key file is then automatically generated at path_to_folder/hashed_passwords1546.key
1546 here is a random number generated when .Hasher.generate() is called.

Then, when you need to use hashed_passwords, you can use the legacy way:

authenticator = stauth.Authenticate(
    names, usernames, 'some_cookie_name',
    'some_signature_key', cookie_expiry_days=30,
    hashed_passwords=hashed_passwords,
)

Or you can alternatively use the saved hashed_passwords1546.key file:

authenticator = stauth.Authenticate(
    names, usernames, 'some_cookie_name', 
    'some_signature_key', cookie_expiry_days=30
    hashed_passwords_path="path_to_folder/hashed_passwords1546.key"
)

I already implemented most of it for my use, so if you think this a good idea, I could raise a PR.

Best regards,
Alex

Unsafe characters allowed in username creation

Currently there is no restriction on characters in a username, which can result in security issues if the value of the username is not handled properly post authentication. Example:

Screen Shot 2023-03-15 at 8 43 48 AM

Would you be open to allowing only alphanumeric + _ , or alternatively to let the auth module take a username validator as an optional parameter to decide the allowed character set?

streamlit.errors.StreamlitAPIException: Values for st.button, st.download_button, st.file_uploader, and st.form cannot be set using st.session_state.

When I run my code, Streamlit throws an API exception. Here is the code that is concerns this problem:

import sqlite3

from CRM.main import crm, stauth
from projectBoard.toDo import *

connproj = sqlite3.connect('projectBoard/projectData.db')
cproj = connproj.cursor()
conncrm = sqlite3.connect('CRM/userData.db')
ccrm = conncrm.cursor()
st.session_state.update(st.session_state)
selectedPage = st.sidebar.selectbox("Page", ["Project Board", "CRM (unfinished)"])
loginbutton = st.sidebar.button("Log in")
if loginbutton:
    crm(conncrm, ccrm)
    selectedPage = "Log In"
elif selectedPage == "Project Board":
    projectboard(cproj, connproj)
import streamlit as st
import streamlit_authenticator as stauth

from CRM.setupdb import loaddb


def crm(conn, c):
    st.title("Log In")
    loaddb(conn, c)
    print(c.execute("SELECT email FROM userTable").fetchall())
    authenticator = stauth.Authenticate(c.execute("SELECT email FROM userTable").fetchall(), c.execute("SELECT username FROM userTable").fetchall(), c.execute("SELECT password FROM userTable").fetchall(), "CRM", "CRM")
    name, authentication_status = authenticator.login('Login', 'main')

Get passwords from Database

Hi,

I am trying to get my passwords with a select query from the database, but when I pass it to the Hasher module, I get an error:

File "/home/appuser/venv/lib/python3.9/site-packages/streamlit_authenticator/init.py", line 37, in hash

return bcrypt.hashpw(password.encode(), bcrypt.gensalt()).decode()

AttributeError: 'tuple' object has no attribute 'encode'

What type of object should be passed to the Hasher module?

I am very new to python and will appreciate your help tremendously.

Request for help

Respected sir,
Kindly help me how to increase the size of message input box to 1 GB from 1MB. I am able to do it for file uploader, but not for message input box.

Regards,
Satish

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.