I need help architecting a Streamlit application that lets the user authenticate with Microsoft’s Single Sign On (SSO) flow. Specifically, the application displays a URL using st.write, for the user to visit, retrieve an authentication token, type it into the chat_input window, and then authenticate with the Microsoft SSO API.
The problem I’m running into is that because the st.chat_input() function is non-blocking, the authentication function is run before the authentication token is entered by the user. Below is a snippet that outlines how I’m trying to develop it.
The place where I could use some help is how to implement the [WAIT UNTIL THE USER RETURNS A VALUE] section. Or otherwise, if I’m using the Streamlit paradigm completely wrong, any architecture advice would be great.
st.write("Please visit (this link) and enter your authentication information in the text box below.")
message = {"role": "assistant", "content": response}
st.session_state.messages.append(message)
if token := st.chat_input():
st.session_state.messages.append({"role": "user", "content": token})
with st.chat_message("user"):
st.write(prompt)
will let us pass only once. If there are function, etc that triggers a code rerun from top to bottom, we cannot pass through it again.
I make a sample code that you can run and experiment with.
import streamlit as st
from streamlit import session_state as ss
# Step 1: Create a session variable to store the response.
# The reason why we are doing this is because we can access
# the response anywhere in the code. The initial value is None.
if 'response' not in ss:
ss.response = None
# Step 2: Define a function to authenticate the user.
def authenticate_user(token):
"""Save the response to session variable."""
response = f'hello {token}' # you real stuff here
# Save a sample response to session variable.
ss.response = f'Your token is {token}, and my response is {response}.'
# Step 3: Show the link to user
st.write("Please visit (this link) and enter your authentication \
information in the text box below.")
# Step 4: Ask the user to input the token.
# Careful with the statement, it will only allow us to pass once.
if token := st.chat_input():
# This will trigger a code rerun from top to bottom and as a result
# we cannot enter here again because of that
# "if token := st.chat_input():" above.
# That is why we save the response in session variable.
# There are techniques to re-enter here but will not do so because
# I am not familiar enough of your app.
authenticate_user(token)
# Step 5: Show the contents of response.
st.write(f'response: {ss.response}')
Thank you @ferdy for your in-depth and quick response. This helps me get closer to the answer, but doesn’t reflect how the API’s authenticate function works. Below I’ve updated the pseudocode to reflect how the API’s authenticate function works. Specifically, it shows the issue in that I need the user to type in the token in step 2.2, which occurs inside the API’s authentication function.
So, my question is whether there is a way to send the input from st.chat_input() into the authenticate_user() function when it is inputted in Step 2.2.
Thanks again for your help!
import streamlit as st
from streamlit import session_state as ss
# Step 1: Create a session variable to store the response.
# The reason why we are doing this is because we can access
# the response anywhere in the code. The initial value is None.
if 'response' not in ss:
ss.response = None
# Step 2: Define a function to authenticate the user.
def authenticate_user():
# Step 2.1: Show the link to user to retrieve the token
st.write("Please visit (this link) and enter your authentication \
information in the text box below.")
# Step 2.2 Ask the user to return the token received from the link using the text box.
"""Save the response to session variable."""
response = token # the token received here
# Step 2.3 Run function to authenticate here
authenticate_token(token)
# Save a sample response to session variable.
ss.response = f'Your token is {token}, and my response is {response}.'
# Step 4: Ask the user to input the token.
# Careful with the statement, it will only allow us to pass once.
if token := st.chat_input():
# This will trigger a code rerun from top to bottom and as a result
# we cannot enter here again because of that
# "if token := st.chat_input():" above.
# That is why we save the response in session variable.
# There are techniques to re-enter here but will not do so because
# I am not familiar enough of your app.
authenticate_user()
# Step 5: Show the contents of response.
st.write(f'response: {ss.response}')
ss.response = f'Your token is {token}, and my response is {response}.'
but response is the same as token.
Also, what does calling authenticate_token do? We are not looking at the return value so it must have some side effect but it is not clear what it is and how it would be relevant to your app.
Thanks @Goyo for your quick reply. To answer your question about the authentication_token() function, it’s a function that provides a URL, that the user must visit to authenticate and receive an authentication token. Then, the function returns the authentication token to complete the authentication.
The following line, isn’t required, so I won’t try to explain to focus on the key issue: ss.response = f'Your token is {token}, and my response is {response}.
# Step 2.2 Ask the user to return the token received
# from the link using the text box.
st.text_input('Input token', key='token', on_change=authenticate_token)
Utilize the on_change parameter to call the function authenticate_token which is defined below.
# Step 1.1: Define a function to authenticate the token.
def authenticate_token():
"""Generates response based on token.
This function is called whenever there are changes to text input
widget at step 2.2 to get the token. The token is taken based from
the key of that text input widget.
"""
token = ss.token
is_token_ok = True # is_token_ok = is_valid_token(token)
if is_token_ok:
response = f'hello {token}'
ss.response = f'Your token is {token}, and my response is {response}.'
else:
ss.response = None
Full revised sample code
import streamlit as st
from streamlit import session_state as ss
# Step 1: Create a session variable to store the response.
# The reason why we are doing this is because we can access
# the response anywhere in the code. The initial value is None.
if 'response' not in ss:
ss.response = None
# Step 1.1: Define a function to authenticate the token.
def authenticate_token():
"""Generates response based on token.
This function is called whenever there are changes to text input
widget at step 2.2 to get the token. The token is taken based from
the key of that text input widget.
"""
token = ss.token
is_token_ok = True # is_token_ok = is_valid_token(token)
if is_token_ok:
response = f'hello {token}'
ss.response = f'Your token is {token}, and my response is {response}.'
else:
ss.response = None
# Step 2: Define a function to authenticate the user.
def authenticate_user():
# Step 2.1: Show the link to user to retrieve the token
st.write("Please visit (this link) and enter your authentication \
information in the text box below.")
# Step 2.2 Ask the user to return the token received
# from the link using the text box.
st.text_input('Input token', key='token', on_change=authenticate_token)
# Step 4: Prompts the user.
# Careful with the statement, it will only allow us to pass once.
if prompt := st.chat_input():
# This will trigger a code rerun from top to bottom and as a result
# we cannot enter here again because of that
# "if token := st.chat_input():" above.
# That is why we save the response in session variable.
# There are techniques to re-enter here but will not do so because
# I am not familiar enough of your app.
authenticate_user()
# Step 5: Show the contents of response.
st.write(f'response: {ss.response}')
Thanks for stopping by! We use cookies to help us understand how you interact with our website.
By clicking “Accept all”, you consent to our use of cookies. For more information, please see our privacy policy.
Cookie settings
Strictly necessary cookies
These cookies are necessary for the website to function and cannot be switched off. They are usually only set in response to actions made by you which amount to a request for services, such as setting your privacy preferences, logging in or filling in forms.
Performance cookies
These cookies allow us to count visits and traffic sources so we can measure and improve the performance of our site. They help us understand how visitors move around the site and which pages are most frequently visited.
Functional cookies
These cookies are used to record your choices and settings, maintain your preferences over time and recognize you when you return to our website. These cookies help us to personalize our content for you and remember your preferences.
Targeting cookies
These cookies may be deployed to our site by our advertising partners to build a profile of your interest and provide you with content that is relevant to you, including showing you relevant ads on other websites.