Why session state is not persisting between refresh?

Summary

I’m trying to persist the authentication token of my app in a session state, but this gets lost when the browser rerun.

Steps to reproduce

Apologies if the code is not exactly as the one in writing, but I’m doing this by heart.

Code snippet:
Main.py

If 'token' is not in st.session_state:
   st.session_state.token = something

else
   # use the session state value

There is of course much more logic in my code, but on the browser refresh, I was expecting token to be in the state hence the else condition block to be executed.

I’ve seen a couple of posts suggesting a variable to be initialised with the st.empty() but I’m not sure that is pointing me in the right direction.

So I wonder if I have completely misunderstood the session state mechanism.

Thanks for clarifying.

Refreshing the browser ends your session and creates a new one, so session_state is refreshed too, as well as the widgets state.

1 Like

As Goyo mentioned, session state is linked to each individual “session”.
When you refresh the browser you start a new session.

Is the token for each individual user, or one token for all users (for example, an API token that should be shared between users to all access the data)?

Tokens is a Google ouath one which has to be refreshed periodically too.

Thanks both for clarifying the session bit. Coming more from the coding perspective where a session ends only by inactivity, this is very confusing.

I think somehow this should be mentioned in this page

Perhaps you could try the memo streamlit function?

Set the ttl to the period you want the Google auth token to refresh.
For example, if the token refreshes every 24 hours, then set

ttl = 24 times 60 times 60 (since it is in seconds).

In this way, only once every 24 hours streamlit app will call the token.
Please let us know how you get on!

EDIT: Had to change * to “times” since it just made stuff italic!
Also changed memo to singleton.
Now changed back to memo since singleton does not have ttl.
Sorry!

As far as I know the OAuth from google does not allow you to specify any TTL. All tokens are expiring one hours after as per the returned expires_in object.

But that’s not going to be a problem as far as I can tell. Given Streamlit logic to run the full app from the beginning, it’s just a case to call in for a refresh at every execution?
The only downside, is that I’ve done it but I don’t see my access_token being refreshed when done in the webapp.
The same principle with a command line POST returns a new one, so I’m now sure I’m eventually getting the token refreshed.

Ah sorry, that wasn’t too clear.
I mean you can set ttl in the streamlit function st.experimental_memo - Streamlit Docs.

If you set this ttl to one hour (i.e. ttl = 1 times 60 times 60) then the function that you use in your Python code to call the OAuth will only update every 1 hour.
i.e. the token you get from OAuth will be stored in a cache and every time you run the app it will be served to you (without contacting Google), until after 1 hour it will again call the function and get the new token from Google.

Perhaps it is worthwhile reading the link above, or even the old cache function

I understand what you mean, but I doubt it will work. Unless refreshed, the OAuth2 token will expire anyway.
But I think I have figured out how to make it.

How did you end up solving this? I am in a similar situation.

1 Like

The problem of making state persist across sessions can be solved in two ways:

  • Using streamlit cache, experimental_memo or experimental_singleton, as suggested above.
  • Using an external storage solution that you can control, like a database.

If you have a problem specific to Google OAuth tokens, I can’t be of any help without more details, because I don’t know how or when they need to be refreshed.

I’m using session_state, but when I lock my phone and then want to follow the conversion on my app, it clears everything up. Why is the session_state not persisting?

Should I use the newer Caching - Streamlit Docs? What are best practices to store the conversation?

I don’t quite understand your description of the issue, but the only reason for session_state not persisting is that the session ends.

On the other hand, a bug in your code might make session_state not store what you think it should be storing.

How do I prevent the session from ending? Here is the code. I know it’s saving the data because I use the session_state to display the current conversation. Here is the live app.

Usually a session ends when the broser tab is closed or refreshed. I guess it can also happen after a long time of inactivity or conectivity loss.

Gotcha. I guess iOS closes the connection if I lock the phone. Is there a way to catch the session_state before it resets? Or just give up and create user authentication and save the conversation on a separate database?

Storing the session data in a way that it can be recovered from another session is easy enough, either in the app server or external storage.

The challenge here is that, when a new session start, there is no builtin mechanism to link it to a previous session. You would need to implement some kind of user management and link sessions to users or use cookies to link sessions to browsers.

I have a way of linking sessions (namely running behind Oauth proxy).
How can I connect them?
Loading a saved session would be easy enough.
Saving the session, however, can be expensive and should preferably not be done unless the previous session is closed.
How can I safely save the session without running the serialisation code on each app rerun?

Is there a good way to handle cookies? Maybe that way, we can do session tokens

The streamlit-authenticator is using cookies. It could be interesting to look at its source code.