Chainlit / chainlit

Build Conversational AI in minutes ⚡️
https://docs.chainlit.io
Apache License 2.0
7.1k stars 930 forks source link

Feature: Make HTTP Headers Available on Start or UserSession #964

Open christoferson opened 5 months ago

christoferson commented 5 months ago

Is your feature request related to a problem? Please describe. I am hosting the app in front of a load balancer that does the Authentication and the results are sent as HTTP Headers to the Application. I would like to access the username from the Headers that are passed in. However I cannot find a callback to access the values.

Describe the solution you'd like Would be great if we can have the HTTP headers made available in the @cl.on_chat_start or make it available in the UserSession object.

Describe alternatives you've considered Create Custom Javascript to fetch the information via websockets. Not all hosting environments support WS connection. Also, having it part of the built in callbacks and API is cleaner.

wfjt commented 5 months ago

You can do this in socketio.pu, the @connect callback receives the asgi environ, didn't test but you could put this at the end of @connect and try it out, just after the ws session is initialized:

    asgi_scope  = environ.get("asgi.scope", {})
    headers: List[Tuple[bytes, bytes]] = asgi_scope.get("headers", {})
    headers_dict: Dict[str, str] = {}
    headers = [headers_dict.update({k.decode("utf-8"): v.decode("utf-8")})
               for k, v in headers if k.decode("utf-8") != "authorization"]

    setattr(ws_session, "headers", headers)
    # from chainlit.session import ws_sessions_id, ws_sessions_sid
    ws_sessions_id[session_id] = ws_session
    ws_sessions_sid[sid] = ws_session
    if session_id in user_sessions:
        user_sessions[session_id]["headers"] = headers_dict.deepcopy()

Didn't check the session handling logic, not sure if these would get overwritten but mostly they seem to check if their session id is found in one of those three and if so the value is used.

It's not clear to me how the session ID flows from the ws endpoint to context.session, maybe one of those emitter events triggers this. No time to comb through it all.

If the headers don't propagate you could always add a global headers_dict at the end and in on @on_chat_start do from chainlit.socket import headers_dict and put in cl.user_session yourself.