Streamlit-Authenticator
Streamlit-Authenticator copied to clipboard
Using the Authenticator with credentials stored in a remote database
Hi - Can we use the Authenticator when credentials are stored in a remote database?
P.S - Did not find a place to post question, hence posting as an issue. Sorry if that is not per guidelines.
Hi @njt1980, thank you for reaching out. It can be done and perhaps this video can help. In the future, I plan on releasing a version that supports hosting the credentials on a remote database. Until then please stay tuned!
Thank you for the prompt reponse. I kind of put together some skeleton code for a login page. It does not throw any error, but I see that, the execution seems to be stopping at
name, authentication_status, username = authenticator.login({'sidebar'}) and the print statement after that does not seem to be executing. Just wanted to check if I am doing anything wrong. Any direction would be great.
Below is the full code for the page
import streamlit as st
import streamlit_authenticator as stauth
import os
import sqlite3
#Connect to remote database and retrieve user credentials if available
def get_user_credentials(username):
connection = sqlite3.connect(r"C:\Users\reservation_system.db")
cursor = connection.cursor()
#Query to get user details
cursor.execute("SELECT name,hashed_password FROM credentials WHERE username = ?",(username,))
user = cursor.fetchone()
connection.close()
if user:
return user[0],user[1]
return None, None
# Assume the user enters their username and password in a login form
input_username = st.text_input("Username")
input_password = st.text_input("Password", type="password")
if st.button("Login"):
name, hashed_password = get_user_credentials(input_username)
print("name :",name)
print("input_username :", input_username)
print("hashed_password :",hashed_password)
if name and hashed_password:
print("Creating authenticator object...")
# Authenticate the user with the retrieved hashed password
# authenticator = stauth.Authenticate([name],
# [input_username],
# [hashed_password],
# "user_cookie",
# "cookie_key",
# cookie_expiry_days=1)
authenticator = stauth.Authenticate({"usernames":{
input_username:{
"name":name,
"password":hashed_password
}}
},
"user_cookie",
"cookie_key",
)
# Perform authentication
print("Authenticating...")
name, authentication_status, username = authenticator.login({'sidebar'})
print("Authentication status :",authentication_status)
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')
else:
st.error("Username not found")
Incredible package, so appreciated. Associated with this would be the ability to send email/username input and hashed password input to the authenticator. That way I can call remote db to retrieve a single user with one hashed password for the authenticator to match against instead of a big payload of all users
That or allow the authenticator to give us the email input to make a small payload db call before matching passwords?
Incredible package, so appreciated. Associated with this would be the ability to send email/username input and hashed password input to the authenticator. That way I can call remote db to retrieve a single user with one hashed password for the authenticator to match against instead of a big payload of all users
That or allow the authenticator to give us the email input to make a small payload db call before matching passwords?
This is in the pipeline and I hope to release it in Q4 of this year. Please stay tuned!
Awesome. And if the ability is there to debundle username/email and password inputs from the authenticator so they can be sent as inputs to a non-render version of it, that allows us to use OAuth for authentication then use your authenticator to handle setting the cookies and session states
Awesome. And if the ability is there to debundle username/email and password inputs from the authenticator so they can be sent as inputs to a non-render version of it, that allows us to use OAuth for authentication then use your authenticator to handle setting the cookies and session states
Yeap, I will consider serving the logic as a service running on a backend server that the user can interface with.
I don't know if this is relevant to the discussion, but I use Supabase as a remote DB to hold my authenticator credentials.
I can't quite email a username/password to it, but I can edit the table by hand (which is really just a row holding the JSON) and add a user if I want.
Thank you very much for this great library! In my case, I am using Google Firestore. I deployed my app to streamlit.app and it is working properly.
@felipecordero Can you maybe make a pull request of your implementation? Or put a link here, so that others can use it as well. Thanks
Hi @morphpiece and thank you for your patience :)
My code is somehow very specific, so I think a pull request could be not fitting everyone approach. But here there is a piece of code from what I implemented:
(Also, feel free to explore the firebase_admin documentation: https://firebase.google.com/docs/admin/setup?hl=en#python)
import firebase_admin
import streamlit_authenticator as stauth
from firebase_admin import credentials, firestore
# Initialize Firebase
if not firebase_admin._apps:
cred = credentials.Certificate(st.secrets["db_name"].to_dict())
firebase_admin.initialize_app(cred)
# Starting communication with the firebase db
db = firestore.client()
# Here I read my collection with credentials
cred_ref = db.collection('credentials')
creds = cred_ref.stream()
config = {}
for doc in creds:
doc_dict = doc.to_dict()
config[doc.id] = doc_dict
config = config["credentials"]
# Pre-hashing all plain text passwords once
stauth.Hasher.hash_passwords(config['credentials'])
# sample code for saving new credentials
def write_credentials_config_firestore(db: firestore.client, config: dict):
main_collection = db.collection("credentials")
main_collection_doc_ref = main_collection.document("credentials")
main_collection_doc_ref.set(config)