Hi @Mohamed thanks for your quick reply. Indeed, the webauth_session cookie was set during the login thru Active Directory, not using Streamlit. Iām talking about a deployed service.
Itās also difficult to debug, because in local deployment there is no webauth_login, and all the cookies appear ā¦ the problem is to get all the cookies in a deployed service.
If I run the script in this way:
cookies = cookie_manager.get_all()
cookies = cookie_manager.get_all()
st.write(cookies)
I get an error:
streamlit.errors.DuplicateWidgetID: There are multiple identical `st.extra_streamlit_components.CookieManager.cookie_manager` widgets with
`key='get_all'`.
To fix this, please make sure that the `key` argument is unique for
each `st.extra_streamlit_components.CookieManager.cookie_manager` you create.
so I run it in this way:
cookies = cookie_manager.get_all(key='1')
cookies = cookie_manager.get_all(key='2')
st.write(cookies)
But still I canāt see the required cookie containing the web authentication info, in the deployed service.
There is any limitation of this package related to the āHttpOnlyā or āSecureā cookie types?
If you set a cookie through the console, such as document.cookie="new_cookie=new_value123" it will show up with cookies = cookie_manager.get_all(). The fact that your cookie was set with AD, make me think it was added with some restrictions, like it got be only accessed from certain domains. Other than that I doubt itās a problem with the CookieManager.
@Mohamed thanks for your answer. At the end I was able to get the cookie that I was looking for, using this package: from streamlit.server.server import Server
Then I compared the cookies coming from the headers (in the server) with the user cookies from your package to find a match of āajs_anonymous_idā. In that way I got the email of the user after decoding the cookie. And finally Iām using the email to send back email notifications, but also to provide secure access to pages based on a table of privileges.
Hi @Mohamed I will add some of the lines to run the code:
The only missing part here is to do a function to decrypt your cookies containing the email from the AUTH login server.
from streamlit.server.server import Server
import extra_streamlit_components as stx
from tornado import httputil #Handle Headers
def get_headers():
# Hack to get the session object from Streamlit.
headers=[]
current_server = Server.get_current()
if hasattr(current_server, '_session_infos'):
# Streamlit < 0.56
session_infos = Server.get_current()._session_infos.values()
else:
session_infos = Server.get_current()._session_info_by_id.values()
# Multiple Session Objects?
for session_info in session_infos:
headers.append(session_info.ws.request.headers)
return headers
def get_email():
#here code your function to decrypt the cookies and get the email from the JSON body
return email
def get_email_from_cookies():
cookie_manager = get_manager()
cookies = cookie_manager.get_all()
headers = get_headers()
for header in headers:
for (k, v) in sorted(header.get_all()):
if k == 'Cookie':
temp_cookie = httputil.parse_cookie(v)
try:
if cookies['ajs_anonymous_id'] in temp_cookie['ajs_anonymous_id']:
email = get_email(temp_cookie)
st.session_state['email'] = email
except:
continue
#Finally just run:
get_email_from_cookies()
This is amazing @MarceTU . Thank you for posting this. Was looking into http cookies, or headers from Streamlit apps for ages! This just made my week! Cheers!!
Well the definition of cloud is broad. But if you specifically mean share.streamlit.io, which its on device cookies are accessible by your application same to otherās, then itās a security issue. Which I am not sure if itās allowed anymore to do on share.streamlit.io.
However if you host your Streamlit application on a domain/subdomain only accessible by your application then it shall not be an issue and you can easily set cookies using cookie manager.
TLDR; Itās highly not advised to set user cookies on share.streamlit.io
Iām running into troubles with the CookieManager and getting cookies. I can successfully add cookies to the browser - I can see them in the developer tools. However, when I try getting the cookie, all I get is None. Thoughts, suggestions?
import extra_streamlit_components as stx
import streamlit as st
@st.cache(allow_output_mutation=True, suppress_st_warning=True)
def get_cookie_manager():
return stx.CookieManager()
cookie_manager = get_cookie_manager()
cookie_name = "Cookie Test"
cookie_value = cookie_manager.get(cookie=cookie_name)
print(f"Cookie value: {cookie_value}")
if cookie_value is None:
cookie_value = ""
with st.form(key="Cookie"):
cookie_value = st.text_input(label="Cookie value:", value=cookie_value)
submitted = st.form_submit_button("Submit")
if submitted:
print(f"Submitting: {cookie_value}")
cookie_manager.set(cookie=cookie_name, val=cookie_value)
print(f"After set: {cookie_manager.get(cookie=cookie_name)}")
I figured out the problem. I had to change the cookies settings in Chrome to āAllow all cookiesā.
However, I still have a problem. When running my streamlit app I can refresh the browser and my cookie will be retrieved. However, if I stop and restart my streamlit app, the cookie isnāt found despite it showing up in the cookies in the developer tools.
Hey there, thanks for making this. Iām having some problems with st.error, st.status, or st.success alongside cookies; here is a minimum reproducible example with streamlit 1.10.0
import streamlit as st
import extra_streamlit_components as stx
@st.cache(allow_output_mutation=True)
def get_manager():
return stx.CookieManager()
cookie_manager = get_manager()
button = st.button("Get cookies")
if button:
st.subheader("All Cookies:")
cookies = cookie_manager.get_all()
st.write(cookies)
st.success("This should show up for longer than a split second")
The green st.success box shows up for only a split second. Any help is much appreciated!
Edit: After posting this, I realized an example above worked fine using forms. As such, here is an extraordinarily hacky way to solve this bug.
import streamlit as st
import extra_streamlit_components as stx
@st.cache(allow_output_mutation=True)
def get_manager():
return stx.CookieManager()
cookie_manager = get_manager()
with st.form(key="Cookie"):
hide_streamlit_style = """
<style>
[data-testid="stForm"] {border: none; padding: 0;}
</style>
"""
st.markdown(hide_streamlit_style, unsafe_allow_html=True)
submitted = st.form_submit_button("Get cookies")
if submitted:
st.subheader("All Cookies:")
cookies = cookie_manager.get_all()
st.write(cookies)
st.success("This should show up for longer than a split second")
Iāve created a function that gets all cookies from the client, including HTTP-only cookies. The other functions posted by the users get all the cookies from all the sessions connected to the streamlit server. This is bad for security issues if you search for authentication cookies. Here I have a function that gets only the cookies for the client:
import re
from streamlit.server.server import Server
from streamlit.scriptrunner import add_script_run_ctx
def get_cookies() -> dict:
session_id = add_script_run_ctx().streamlit_script_run_ctx.session_id
session_info = Server.get_current()._get_session_info(session_id)
header = session_info.ws.request.headers
header = dict(header.get_all())
cookies_str = header["Cookie"]
results = re.findall(r"([\w]+)=([^;]+)", cookies_str)
cookies = dict(results)
return cookies
when I tried implementing in my app, it caused all sorts of unexpected behavior and was breaking my scripts. Turns out that calling cookie_manager causes the app.py script to run multiple times, and returns the cookies only on the last run. To test, I used session state to track the number of runs and the result:
@st.cache(allow_output_mutation=True)
def get_manager():
return stx.CookieManager()
cookie_manager = get_manager()
cookies = cookie_manager.get_all()
if 'counter' not in st.session_state:
st.session_state['counter'] = 0
st.session_state['result'] = {}
st.session_state['counter'] = st.session_state['counter'] + 1
st.session_state['result'][st.session_state['counter']] = cookies
st.write(st.session_state['result'])
Result:
As you can see, the full script ran top to bottom 3 times before finally returning the cookies. That was the first run after starting the server. If I refresh the page, it will only run twice.
If I change ācookies = cookie_manager.get_all()ā to "cookies = {āmyā: ācookieā}, the script only runs once as expected:
Is this the intended behavior? Iām guessing this is the reason many are having trouble getting it to work.
see my post just above. when get_manager() is called, the script is trigger to run multiple times, it doesnāt return the cookies until the second or third pass. You need to write your script in such a way that it waits until the cookies are returned until proceeding.
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.