Making User Login Application with Streamlit

Oğuzhan Arı
7 min readMay 14, 2024

--

You need a small user login application for a very simple need, but you don’t want to deal with neither hosting, html, css or anything else. here is, again, a perfect opportunity for you! a great application with a database of google sheets, running entirely on streamlit and consisting of only 54 lines of code.

First of all, we define a user_state to track the current state of the user. user_state allows us to track the current state of the user and make the application behave accordingly.

import streamlit as st

st.title('Amazing User Login App')

# Create user_state
if 'user_state' not in st.session_state:
st.session_state.user_state = {
'username': '',
'password': '',
'logged_in': False
}

When the application is loaded, since there is no user_state in the session_state, we create it directly and enter the information we want to store in it.
If our user is not logged in, we want a login button to appear in front of the user.

if not st.session_state.user_state['logged_in']:
# Create login form
st.write('Please login')
username = st.text_input('Username')
password = st.text_input('Password', type='password')
submit = st.button('Login')

then we need to test whether the user is a correct user. when the button we assign to the submit variable is pressed, we want to log in. first of all, to test the general logic, we try a scenario where the username is admin and the password is 1234.

# Check if user is logged in
if submit and st.session_state.user_state['logged_in'] == False:
if username == 'admin' and password == '1234':
st.session_state.user_state['username'] = username
st.session_state.user_state['password'] = password
st.session_state.user_state['logged_in'] = True
st.write('You are logged in')

if the user’s name and password are correct, we assign the user’s information to user_state in session_state. if the information is not correct, we print it to the screen.

        else:
st.warning('Invalid username or password')

our whole entry process should be seen as follows.

if not st.session_state.user_state['logged_in']:
# Create login form
st.write('Please login')
username = st.text_input('Username')
password = st.text_input('Password', type='password')
submit = st.button('Login')

# Check if user is logged in
if submit and st.session_state.user_state['logged_in'] == False:
if username == 'admin' and password == '1234':
st.session_state.user_state['username'] = username
st.session_state.user_state['password'] = password
st.session_state.user_state['logged_in'] = True
st.write('You are logged in')
st.rerun()
else:
st.warning('Invalid username or password')

here, the most important thing that is not above is the st.rerun() detail. our goal here is that after updating user_state, we want the application to run again according to the new user state. the information about the user is not lost because it is stored in session_state.
When our application runs again, our st.session_state.user_state[‘logged_in’] value will now be True, so we define a logic for this.

elif st.session_state.user_state['logged_in']:
st.write('Welcome to the app')
st.write('You are logged in as:', st.session_state.user_state['username'])

our whole code looks like this;

import streamlit as st

st.title('Amazing User Login App')

# Create user_state
if 'user_state' not in st.session_state:
st.session_state.user_state = {
'username': '',
'password': '',
'logged_in': False
}

if not st.session_state.user_state['logged_in']:
# Create login form
st.write('Please login')
username = st.text_input('Username')
password = st.text_input('Password', type='password')
submit = st.button('Login')

# Check if user is logged in
if submit and st.session_state.user_state['logged_in'] == False:
if username == 'admin' and password == '1234':
st.session_state.user_state['username'] = username
st.session_state.user_state['password'] = password
st.session_state.user_state['logged_in'] = True
st.write('You are logged in')
st.rerun()
else:
st.write('Invalid username or password')
elif st.session_state.user_state['logged_in']:
st.write('Welcome to the app')
st.write('You are logged in as:', st.session_state.user_state['username'])

but here we don’t have a situation like adding any user, that is, updating our application remotely. for this we need a database, for that we will get help from google sheets.
firstly we create a google sheet. in it we define mail_adress, name_surname, user_type, password and fixed_user_message variables.

we make this google sheets accessible to everyone. then we copy the link

we create a folder named .streamlit inside our work. we add a file named secrets.toml inside this folder. since you do not want the link in question to be viewable by everyone, we will store the url of the sheets in this file. our url looks like this

https://docs.google.com/spreadsheets/d/1UduSnVilnrfISEg2uVWqdKLl8aiHGQbsPo_UjyBbj4s/edit?usp=sharing

We change the /edit?usp=sharing part at the end of this link to /export?format=csv and add it to our secrets.toml file with the variable named database_url.

By adding the request and pandas libraries to our work file, we prepare our code that will call the file in question and save it as a pandas dataframe in a variable named database

import streamlit as st
import pandas as pd
import requests as rs

st.title('Amazing User Login App')

sheet_csv = st.secrets["database_url"]
res = rs.get(url=sheet_csv)
open('database.csv', 'wb').write(res.content)
database = pd.read_csv('database.csv', header=0)

The code above reads the link from the secrets file and saves it to the database.csv file. then we read it with the pandas library.

update user_state according to our database.

# Create user_state
if 'user_state' not in st.session_state:
st.session_state.user_state = {
'name_surname': '',
'password': '',
'logged_in': False,
'user_type': '',
'mail_adress': '',
'fixed_user_message': ''
}

we will also update our login control logic.

if not st.session_state.user_state['logged_in']:
# Create login form
st.write('Please login')
mail_adress = st.text_input('E-Mail')
password = st.text_input('Password', type='password')
submit = st.button('Login')

# Check if user is logged in
if submit:
user_ = database[database['mail_adress'] == mail_adress].copy()

The code above limits the dataframe with the e-mail address entered instead of the user’s e-mail address and performs checks only for the current user.

if user_['mail_adress'].values[0] == mail_adress and user_['password'].values[0] == password:
st.session_state.user_state['mail_adress'] = mail_adress
st.session_state.user_state['password'] = password
st.session_state.user_state['logged_in'] = True
st.session_state.user_state['user_type'] = user_['user_type'].values[0]
st.session_state.user_state['mail_adress'] = user_['mail_adress'].values[0]
st.session_state.user_state['fixed_user_message'] = user_['fixed_user_message'].values[0]
st.write('You are logged in')
st.rerun()

since the user_ variable in question is still a pandas dataframe, we perform the checks according to the zeroth index of each column. the important detail here is that our program does not yet check whether the user is present in the database or not. and while we’re thinking about it, let’s add this.

if submit:
user_ = database[database['mail_adress'] == mail_adress].copy()
if len(user_) == 0:
st.error('User not found')

our entire entry process looks like this.

if not st.session_state.user_state['logged_in']:
# Create login form
st.write('Please login')
mail_adress = st.text_input('E-Mail')
password = st.text_input('Password', type='password')
submit = st.button('Login')

# Check if user is logged in
if submit:
user_ = database[database['mail_adress'] == mail_adress].copy()
if len(user_) == 0:
st.error('User not found')
else:
if user_['mail_adress'].values[0] == mail_adress and user_['password'].values[0] == password:
st.session_state.user_state['mail_adress'] = mail_adress
st.session_state.user_state['password'] = password
st.session_state.user_state['logged_in'] = True
st.session_state.user_state['user_type'] = user_['user_type'].values[0]
st.session_state.user_state['mail_adress'] = user_['mail_adress'].values[0]
st.session_state.user_state['fixed_user_message'] = user_['fixed_user_message'].values[0]
st.write('You are logged in')
st.rerun()
else:
st.write('Invalid username or password')

Well, we are slowly approaching the end. What if the user information is correct? Firstly, let’s update our database. Let’s have 2 users.

It looks like this for the admin user,

and this is how it looks for the user user,

Let our admin user be different from the standard user and see the database.

elif st.session_state.user_state['logged_in']:
st.write('Welcome to the app')
st.write('You are logged in as:', st.session_state.user_state['mail_adress'])
st.write('You are a:', st.session_state.user_state['user_type'])
st.write('Your fixed user message:', st.session_state.user_state['fixed_user_message'])
if st.session_state.user_state['user_type'] == 'admin':
st.write('You have admin rights. Here is the database')
st.table(database)

Finally, our 54-line app looks like this,

import streamlit as st
import pandas as pd
import requests as rs

st.title('Amazing User Login App')

sheet_csv = st.secrets["database_url"]
res = rs.get(url=sheet_csv)
open('database.csv', 'wb').write(res.content)
database = pd.read_csv('database.csv', header=0)

# Create user_state
if 'user_state' not in st.session_state:
st.session_state.user_state = {
'name_surname': '',
'password': '',
'logged_in': False,
'user_type': '',
'mail_adress': '',
'fixed_user_message': ''
}

if not st.session_state.user_state['logged_in']:
# Create login form
st.write('Please login')
mail_adress = st.text_input('E-Mail')
password = st.text_input('Password', type='password')
submit = st.button('Login')

# Check if user is logged in
if submit:
user_ = database[database['mail_adress'] == mail_adress].copy()
if len(user_) == 0:
st.error('User not found')
else:
if user_['mail_adress'].values[0] == mail_adress and user_['password'].values[0] == password:
st.session_state.user_state['mail_adress'] = mail_adress
st.session_state.user_state['password'] = password
st.session_state.user_state['logged_in'] = True
st.session_state.user_state['user_type'] = user_['user_type'].values[0]
st.session_state.user_state['mail_adress'] = user_['mail_adress'].values[0]
st.session_state.user_state['fixed_user_message'] = user_['fixed_user_message'].values[0]
st.write('You are logged in')
st.rerun()
else:
st.write('Invalid username or password')
elif st.session_state.user_state['logged_in']:
st.write('Welcome to the app')
st.write('You are logged in as:', st.session_state.user_state['mail_adress'])
st.write('You are a:', st.session_state.user_state['user_type'])
st.write('Your fixed user message:', st.session_state.user_state['fixed_user_message'])
if st.session_state.user_state['user_type'] == 'admin':
st.write('You have admin rights. Here is the database')
st.table(database)

that’s all! hope this helps. if you are interested, I can write a section on user registration and approval. until then, take care! ♥️

--

--