Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Consider implementing additional options for login control and providing support for logging out #13

Open
mapix opened this issue Mar 25, 2023 · 11 comments

Comments

@mapix
Copy link
Contributor

mapix commented Mar 25, 2023

Example case:

  • Implementing idpHint login options to allow for better control of idp preferences.
  • Providing an in-place logout function for a more seamless user experience.

I have already implemented these changes in my forked branch. If they are well-received, I would be happy to create a pull request to merge them into the upstream branch.

master...pragmatic-streamlit:streamlit-keycloak:feat/allow-logout

@bleumink
Copy link
Owner

Great stuff, I would happily merge this in. For the logout functionality, we could also go all the way:

  • use the keycloak-js createLogoutUrl method
  • accept logoutOptions
  • expose the logout_url in the keycloak dataclass on the python side

@hansehe
Copy link
Contributor

hansehe commented Apr 27, 2023

Hi, I can see that this feature is merged into the branch feature/logout, and we are working on something that highly depend on using additional login options (basically setting the idp hint option during login). Is it possible to get this functionality out as a beta package or something soon? Maybe even in the master branch?

@bleumink
Copy link
Owner

bleumink commented Apr 30, 2023

Would providing the id token be enough for that? If so, I can merge that into master first.
I was looking at the logout functionality as well, but had some issues getting keycloak-js to generate working logout urls.

edit: and also the login_options of course

@bleumink
Copy link
Owner

bleumink commented May 1, 2023

Merged the changes into master, should have done that earlier. I will look at the logout functionality soon.

@hansehe
Copy link
Contributor

hansehe commented May 3, 2023

Hi again, I'm trying to use the login_options but it doens't seem to work.
So this is the input to the streamlit keycloak login:

keycloak = login(    
            url=settings.url,
            realm=settings.realm,
            client_id=settings.client_id,
            login_options={
                "idpHint": settings.kc_idp_hint,
                "loginHint": "myemail@gmail.com",
            },
            auto_refresh = True
    )   

I'm expecting the 'kc_idp_hint' query parameter to be provided with the login url to keycloak, including the login hint. However none of the parameters are provided in the login url. I've double checked the streamlit keycloak code and I cannot find the reason to the problem. Are you able to understand why it doesn't work?

Thanks a lot for your contributions.

@hansehe
Copy link
Contributor

hansehe commented May 4, 2023

Think I found the bug, and created a PR on it:
#18

@CHerSun
Copy link

CHerSun commented Aug 8, 2023

Could you elaborate on how to log out?

@michal-sensestreet
Copy link

I second the Logout question.

@mapix
Copy link
Contributor Author

mapix commented Sep 25, 2023

@CHerSun @michal-sensestreet
The following example demonstrates the login and logout of streamlit keycloak, the entire experience is very smooth.

import os
from urllib.parse import urlencode

import streamlit as st
from streamlit.runtime import Runtime
from streamlit.runtime.scriptrunner import get_script_run_ctx

from streamlit_keycloak import login


st.title("Streamlit Keycloak Login & Logout example")


def _get_session_id():
    context = get_script_run_ctx()
    if not context:
        return
    return context.session_id


def _get_current_request():
    session_id = _get_session_id()
    if not session_id:
        return None
    runtime = Runtime._instance
    if not runtime:
        return
    client = runtime.get_client(session_id)
    if not client:
        return
    return client.request


def get_web_origin():
    request = _get_current_request()
    return request.headers["Origin"] if request else os.getenv("WEB_BASE", "")


keycloak_endpoint = "https://example.com"
keycloak_realm = "example"


if not st.session_state.get("keycloak_user_info"):
    keycloak = login(
        url=keycloak_endpoint,
        realm=keycloak_realm,
        client_id="example_client",
        init_options={"checkLoginIframe": False},
    )
    if keycloak.authenticated:
        st.session_state.keycloak_id_token = keycloak.id_token
        st.session_state.keycloak_user_info = keycloak.user_info


if st.session_state.get("keycloak_user_info"):
    params = urlencode(
        {
            "post_logout_redirect_uri": get_web_origin(),
            "id_token_hint": st.session_state.keycloak_id_token,
        }
    )
    st.json(st.session_state.keycloak_user_info)
    st.markdown(
        f'Switch account by <a target="_self" href="{keycloak_endpoint}/realms/{keycloak_realm}/protocol/openid-connect/logout?{params}">Logout</a>',
        unsafe_allow_html=True,
    )

@michal-sensestreet
Copy link

thanks @mapix , works like a charm.

@CHerSun
Copy link

CHerSun commented Oct 2, 2023

@mapix thank you! Awesome, love the target="_self" too to make everything work in the same tab.

Do you maybe know if it's possible to login using same tab only too? I.e. without popup on desktop browsers (mobile browsers seem to utilize same tab).

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

5 participants