bleumink/streamlit-keycloak

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

Opened this issue · 12 comments

mapix commented

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

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

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?

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

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

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.

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

Could you elaborate on how to log out?

I second the Logout question.

mapix commented

@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,
    )

thanks @mapix , works like a charm.

@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).

>     if keycloak.authenticated:
>         st.session_state.keycloak_id_token = keycloak.id_token
>         st.session_state.keycloak_user_info = keycloak.user_info
> 

Is it keycloak.id_token (or) keycloak.access_token?