Skip to content

Conversation

@velochy
Copy link
Contributor

@velochy velochy commented Jul 10, 2025

Describe your changes

Currently, st.logout ignores end_session_endpoint (ESE) in the OIDC configuration.
This can cause issues, as some OIDC providers keep their own cookies and skip the login screen if they have an active session.

This change:
a) Writes the name of provider into the session cookie (so it would be clear which provider the user is currently logged into)
b) Makes st.logout redirect to ESE if one is provided.

GitHub Issue Link (if applicable)

Closes #11900

Testing Plan

  • unit tests added both for a case where ESE is provided as well as when not

Contribution License Agreement

By submitting this pull request you agree that all contributions to this project are made under the Apache 2.0 license.

@snyk-io
Copy link
Contributor

snyk-io bot commented Jul 10, 2025

🎉 Snyk checks have passed. No issues have been found so far.

security/snyk check is complete. No issues have been found. (View Details)

license/snyk check is complete. No issues have been found. (View Details)

Copy link
Collaborator

@vdonato vdonato left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Overall this looks reasonable to me, but let me see if I can get a second reviewer from the team that's more familiar with this feature.

I left a few comments with a few nits from a first pass. Note that I haven't given the tests a careful read yet as well.

@sfc-gh-lmasuch sfc-gh-lmasuch requested a review from Copilot July 11, 2025 10:41
Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull Request Overview

This PR enhances the logout flow to support OIDC end_session_endpoint and records the OIDC provider in the session cookie.

  • Store the provider field in the auth cookie during login.
  • Extend AuthLogoutHandler to clear the cookie and redirect to the provider’s end_session_endpoint if present.
  • Add new tests for logout with and without an end_session_endpoint, and update the logout docstring.

Reviewed Changes

Copilot reviewed 3 out of 3 changed files in this pull request and generated 1 comment.

File Description
lib/streamlit/web/server/oauth_authlib_routes.py Implement _get_provider_logout_url, always clear the auth cookie, and redirect to OIDC logout
lib/tests/streamlit/web/server/oauth_authlib_routes_test.py Add tests for logout behavior when an end_session_endpoint is provided or missing
lib/streamlit/user_info.py Update logout() docstring to describe remote OIDC logout support
Comments suppressed due to low confidence (1)

lib/streamlit/web/server/oauth_authlib_routes.py:171

  • Consider adding a test case to cover the branch where the auth cookie does not include an "origin" field, ensuring that the fallback to self.request.protocol and self.request.host is exercised.
            origin = user_info.get("origin")

Copy link

Copilot AI Jul 11, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[nitpick] The test explicitly sets cookie_secret on a new Application instance via self.get_app(), but the AsyncHTTPTestCase harness already applies this secret returned by get_app for handling secure cookies. You can remove this redundant assignment to simplify the test.

Suggested change
self.get_app().settings["cookie_secret"] = "test_cookie_secret"

Copilot uses AI. Check for mistakes.
Comment on lines 173 to 169
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: Wouldn't it be possible to construct this from the configured redirect_uri (the url without /oauth2callback) which I think is required anyways? just protocol and host (or just origin) might be wrong in some setups. E.g. if app is deployed under an url path via a proxy.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is a very good catch and calling it a nit really does not do it justice.
My guess is that without the fix, the code would actually fail under some deployment scenarios.
Thank you for noticing it :)

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think there might still be some deployment scenarios where the current get_origin_from_secrets implementation won't work here. Redirecting to the origin of our redirect_uri may not work in cases where the app isn't being served from the root path of its origin. For example, it's possible to set up an app served from https://my.streamlit.app/path/to/app with redirect url https://my.streamlit.app/path/to/app/oauth2callback for which the redirect after logout will break.

It might be fine to merge this change as-is and make a quick followup since the end_session_endpoint doesn't work at the moment anyway, but it'd be slightly preferable to fix this in this PR.

(This might change the correct way to approach my other comment)

@velochy
Copy link
Contributor Author

velochy commented Jul 11, 2025

Thank you for the quick reply @vdonato !

Do you happen to know what the general policy is here on PRs in terms of addessing multiple issues.

I'm actually thinking of adding the code to also handle #10378 as well as introduce a way to refresh the user data (in case the user changes their settings such as language).

The changes will basically impact the same files and should be easy to review together with what is already there.

I can of course wait for this to get merged and/or do parallel PR-s as well, but doing them together seems a bit more efficient.

@vdonato
Copy link
Collaborator

vdonato commented Jul 11, 2025

Hey @velochy,

I think #10378 is a sufficiently disjoint issue (in terms of functionality) that I'd prefer having a fix for it go in as a second PR, although in general we're not always opposed to handling separate issues in combined PRs.

For this PR, it looks like some of the unit tests in CI are unhappy for whatever reason, but once those are fixed, I think this should be overall good to go, and I can take a second pass in reviewing the code then.

@velochy velochy force-pushed the OIDCLogout branch 2 times, most recently from 5bdfefe to c4b3b79 Compare July 14, 2025 09:29
@velochy
Copy link
Contributor Author

velochy commented Jul 14, 2025

@vdonato fixed all of the nits.

As for the unhappy tests, I'm having trouble reproducing them. Is there documentation somewhere on how to setup min-deps env myself? I see it's python 3.9, but a clean conda with only that still has no issues so it has to be something else there.

@velochy velochy force-pushed the OIDCLogout branch 2 times, most recently from f91f318 to f757726 Compare July 18, 2025 11:16
@velochy
Copy link
Contributor Author

velochy commented Jul 18, 2025

@vdonato figured out why tests were failing. Issue was backwards compatibility w tornado.

@velochy
Copy link
Contributor Author

velochy commented Jul 19, 2025

It seems the tests are now all passing - except the check on labels which I believe one of the maintainers has to fill out?

Is there anything I still need to do for this to get merged? @vdonato

@sfc-gh-lwilby sfc-gh-lwilby added security-assessment-completed Security assessment has been completed for PR change:bugfix PR contains bug fix implementation impact:users PR changes affect end users labels Jul 21, 2025
@vdonato
Copy link
Collaborator

vdonato commented Jul 21, 2025

Hey @velochy, thanks for getting this PR into a good state! And sorry for my radio silence on this PR, I've been caught up with some other work over the past week. Let me give this another read, but assuming the changes made were mostly just to get tests to work again, I'm assuming this change should be more or less good to go.

Copy link
Collaborator

@vdonato vdonato left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Left one comment about addressing some deployment scenarios that I think may still not work + also a nit, but overall this LGTM! This should be good to go once my redirect_uri question is addressed

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: The graphite request for a docstring may be overkill, but it might be useful to tweak this name to be get_redirect_uri_origin_from_secrets or something similar that makes it more clear what origin corresponds to now that the function lives a bit further away from where it's used.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@vdonato just so I understand your idea correctly, would it work if I:

a) change the name like you recommend
b) move the fallback of redirect uri missing here
c) change the fallback to use server.baseUrlPath (if present) ?

Or is there something I'm still not thinking of or misunderstanding?

Copy link
Collaborator

@vdonato vdonato Jul 22, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thinking about this more, I think we might end up needing two separate helper functions since we'll still need this function to get the origin for the other/older use case in AuthCallbackHandler.get (we could probably just keep the _get_origin_from_secrets method where it was and define a new one for the logout redirect url).

The fallback code can stay where it is since passing the request to this helper doesn't seem ideal, and the main functional change we'll want to make is to build post_logout_redirect_uri using server.baseUrlPath so that we handle the case where an app isn't served from the root of its origin.

Another thing that I was worried about is whether we have to consider cases where the Streamlit server thinks the base path where the app is being served is one thing, but the browser thinks it's another (this scenario is somewhat contrived, but I think it's possible if you, for example, have a load balancer in front of your Streamlit instance that receives traffic for the app at one path and routes it to another). I don't think this is an issue, though, because the login URLs generated in user_info.py are set using server.baseUrlPath, so it seems like we already have an implicit assumption that this doesn't happen for the auth feature to work.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think I'm getting confused now, so trying to lay down a clear plan again:

  1. Revert the _get_origin_from_secrets as it was originally for oauthCallback
  2. Instead of using redirect_uri from secrets to construct redirect for logout, just use server.baseUrlPath

Or did you mean something more elaborate still?

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah, I think that's more or less what needs to be done. We are essentially relying on the assumption that our redirect_uri is equal to {origin}/{server.baseUrlPath}/oauth2callback for things to work, but we seem to be making that assumption for login already, so I think it's safe to do the same here.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

After reviewing the code a little, I decided to go for a slightly different solution, and instead of taking server.baseUrlPath I am just stripping /oauth2callback from redirect uri.

The main reason I believe this is the better approach is that for deployments that work at domain root, baseUrlPath might not be set to the correct external URL (as things will work without it), whereas redirect_uri is guaranteed to be the public url or login would fail.

I do have to admit this is a very unfortunate case of duplication, however. In the ideal world, one of those two configuration parameters should be deprecated (with my bet being the redirect uri being the better candidate for it), but this would require a whole process for something as widely used as streamlit, so it might be just a bit too much trouble for the value it would create.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sounds reasonable to me! Agreed on being able to only have one of server.baseUrlPath/redirect_uri would be ideal, but changing things so that we only need one of these two config values is definitely outside of the scope of this PR.

Comment on lines 173 to 169
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think there might still be some deployment scenarios where the current get_origin_from_secrets implementation won't work here. Redirecting to the origin of our redirect_uri may not work in cases where the app isn't being served from the root path of its origin. For example, it's possible to set up an app served from https://my.streamlit.app/path/to/app with redirect url https://my.streamlit.app/path/to/app/oauth2callback for which the redirect after logout will break.

It might be fine to merge this change as-is and make a quick followup since the end_session_endpoint doesn't work at the moment anyway, but it'd be slightly preferable to fix this in this PR.

(This might change the correct way to approach my other comment)

@velochy velochy force-pushed the OIDCLogout branch 2 times, most recently from 52c6305 to c732ffd Compare July 24, 2025 17:37
@vdonato
Copy link
Collaborator

vdonato commented Jul 25, 2025

Thanks for your continued work on this @velochy! This LGTM -- I made one last change to move the new imports to the top of the test file that I thought would be easier to quickly do myself rather than make a request for you to do so.

It looks like there's also still one CI stage that's being problematic, but it seems to be a new one (at least I don't recognize it) that's non-required and failing for reasons unrelated to this change, so this PR should be merge-able once other CI checks pass.

@vdonato vdonato merged commit 98258bf into streamlit:develop Jul 26, 2025
42 of 44 checks passed
@sfc-gh-nbellante
Copy link
Contributor

Hi @velochy a couple issues have come in that we suspect is related to this PR. Any ideas on how to quickly fix these? We'd like to patch this as soon as possible and would need to resort to reverting this PR if we can't find an easy fix.

#12144
#12169

sfc-gh-bnisco added a commit that referenced this pull request Aug 11, 2025
@velochy
Copy link
Contributor Author

velochy commented Aug 12, 2025

@sfc-gh-nbellante it seems both issues should be fixed by afding client_id to the request, which should be quire easy to do. I will create a PR over today with the change

sfc-gh-bnisco added a commit that referenced this pull request Aug 12, 2025
…onfig (#11901)" (#12179)

This reverts commit 98258bf.

## Describe your changes

- For more details see this comment:
#12182 (comment)

## GitHub Issue Link (if applicable)

## Testing Plan

- Explanation of why no additional tests are needed
- Unit Tests (JS and/or Python)
- E2E Tests
- Any manual testing needed?

---

**Contribution License Agreement**

By submitting this pull request you agree that all contributions to this
project are made under the Apache 2.0 license.
sfc-gh-bnisco added a commit that referenced this pull request Aug 12, 2025
…onfig (#11901)" (#12179)

This reverts commit 98258bf.

## Describe your changes

- For more details see this comment:
#12182 (comment)

## GitHub Issue Link (if applicable)

## Testing Plan

- Explanation of why no additional tests are needed
- Unit Tests (JS and/or Python)
- E2E Tests
- Any manual testing needed?

---

**Contribution License Agreement**

By submitting this pull request you agree that all contributions to this
project are made under the Apache 2.0 license.
@velochy
Copy link
Contributor Author

velochy commented Aug 18, 2025

Merged the PR #12182 that adds client_id.

However, two things likely still need doing:
a) id_token_hint needs to be added once #12044 makes it possible (#12144 (comment))
b) see if we can make it redirect to /oauth2callback instead of / to properly bypass uri whitelist checks (#12144 (comment))

@velochy
Copy link
Contributor Author

velochy commented Aug 18, 2025

@sfc-gh-bnisco Can this PR be re-opened? It makes more sense to continue this thread than the #12182 hotfix one.

@sfc-gh-bnisco
Copy link
Collaborator

Hi @velochy, good question! I would like to, but it is not possible to re-open a merged PR in GitHub. We'll have to continue the thread in any other non-merged PR.

@velochy
Copy link
Contributor Author

velochy commented Aug 18, 2025

Understood.

I will open a new PR once #12044 gets merged then

kmcgrady added a commit that referenced this pull request Jan 12, 2026
…2) (#12693)

## Describe your changes

Currently, st.logout ignores end_session_endpoint (ESE) in the OIDC
configuration.
This can cause issues, as some OIDC providers keep their own cookies and
skip the login screen if they have an active session.

This change:
a) Writes the name of provider into the session cookie (so it would be
clear which provider the user is currently logged into)
b) Makes st.logout redirect to ESE if one is provided

This is a revised version of
#11901 to adress the issues
raised in
#12144 (comment)
Most notably:
1) client_id is added to ESE request (original issue, with attempted fix
at #12182)
2) id_token_hint is also added (addressing
#12144 (comment))
3) ESE request redirect target it changed to /oauth2callback (adressing
#12144 (comment))

This is a follow-up to #12044

## GitHub Issue Link (if applicable)

Closes #11900

## Testing Plan

- unit tests added both for a case where ESE is provided as well as when
not

---

**Contribution License Agreement**

By submitting this pull request you agree that all contributions to this
project are made under the Apache 2.0 license.

---------

Co-authored-by: Vincent Donato <vincent@streamlit.io>
Co-authored-by: Ken McGrady <ken.mcgrady@gmail.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

change:bugfix PR contains bug fix implementation impact:users PR changes affect end users security-assessment-completed Security assessment has been completed for PR

Projects

None yet

Development

Successfully merging this pull request may close these issues.

st.logout does not end the session with the OIDC provider

6 participants