Headers not populating with user supplied values
I am able to call the @cl.header_auth_callback , my client does this, it adds a custom test header key and value but the chainlit callback does not show the key, it only has default headers. I have also set the env key os.environ["CHAINLIT_CUSTOM_AUTH"] ="True". What am I missing?
headers = {'test-header':'test-value'} url = "http://localhost:8000" response = requests.get(headers=headers, url=url,allow_redirects=True)
Based on what I found, setting CHAINLIT_CUSTOM_AUTH=true is necessary for custom authentication, but there’s no documentation or examples confirming that custom headers like 'test-header' are filtered or modified before reaching @cl.header_auth_callback. There are no known issues or extra steps documented for passing custom headers to the callback, and your usage of the requests library appears correct. If the callback only shows default headers, it’s possible that Chainlit or its underlying framework may filter out non-standard headers, or the callback is triggered on a different endpoint than your GET request. Double-check that your request targets the exact endpoint that triggers the callback and that the header name matches what the server expects. For reference, the environment variable approach is discussed here: CHAINLIT_CUSTOM_AUTH usage.
To reply, just mention @dosu.
How did I do? Good | Irrelevant | Incorrect | Verbose | Hallucination | Report 🐛 | Other
The callback function is hit in the debugger, it just does not show my custom header which is limiting me to know who is authenticating! In a way, header auth is broken.
Do we have any working samples of header auth documented?
There aren't any official samples or documentation for header-based authentication or custom headers in Chainlit's header_auth_callback. Setting CHAINLIT_CUSTOM_AUTH=true is necessary, but it may not be sufficient if something in your stack (like a proxy, middleware, or even FastAPI/ASGI itself) strips or fails to forward custom headers. Issues with authentication callbacks have also been linked to environment variables like CHAINLIT_ROOT_PATH not being set correctly, which can affect callback behavior example.
A related issue with custom callback endpoints was resolved by using @app.get instead of @router.get for route definitions example. You might want to check if your server or any middleware is filtering out non-standard headers, and try adjusting your route definitions as suggested.
The closest working example for custom authentication is the custom-frontend sample, but it doesn't directly address header-based auth or custom headers in the callback example.
If these steps don't resolve the issue, there may be an undocumented restriction or bug in how Chainlit handles custom headers in authentication callbacks.
To reply, just mention @dosu.
How did I do? Good | Irrelevant | Incorrect | Verbose | Hallucination | Report 🐛 | Other
I tried outside of chainlit and my system forwarded client headers just fine. This is potentially a bad bug, if there is one. It affects adoption as many uses cases need some kind of auth. I was trying oauth, I made the call but there is no documentation on how to pass the token to the callback. Would token and other args go as body parameters?
There isn't any documentation or working sample showing how to pass OAuth tokens or custom arguments to Chainlit's authentication callback via body parameters. From what is known, Chainlit's authentication logic is designed to look for tokens in cookies first and then in the Authorization header as a fallback—not in the request body. There are also reports that large tokens in cookies can cause issues, but the fallback to the Authorization header should work for standard OAuth flows. If your custom headers (including Authorization) aren't reaching the callback, this could be a bug or an undocumented restriction in how Chainlit handles headers before invoking the callback. More details on this behavior are discussed here: JWT/cookie handling and header fallback.
To reply, just mention @dosu.
How did I do? Good | Irrelevant | Incorrect | Verbose | Hallucination | Report 🐛 | Other
It was getting very difficult to debug oauth as I am deploying chainlit to cloud as containers. So I put up an intermediary auth callback to receive token from Google, inspect the token and reattach to make a call to my chainlit callback and it throws the below error.
{"detail":"Missing code or state"}
response = requests.get( "https://mychainlit.oncloud.container.io/auth/oauth/google/callback", headers={"Authorization": f"Bearer {token}"} )
What am I missing, I am certain I am sending a valid bearer token which google gave me in my callback.
The /auth/oauth/google/callback endpoint in Chainlit expects to be called as part of the standard OAuth redirect flow, where Google redirects the user to this endpoint with 'code' and 'state' parameters in the query string. Sending a Bearer token directly to this endpoint (even if valid) will always result in the "Missing code or state" error, because the endpoint is not designed to accept tokens in the Authorization header this way reference.
If you want to authenticate with a Bearer token, Chainlit's authentication logic is designed to look for tokens in cookies first, and then in the Authorization header as a fallback—but this applies to protected API endpoints, not the OAuth callback itself reference. To use OAuth with Chainlit, you need to let the full redirect flow complete, so Google sends the code and state to the callback, and Chainlit exchanges them for a token internally.
If you need a custom flow (for example, to handle tokens directly), you may need to implement a custom authentication endpoint or logic outside the standard OAuth callback.
To reply, just mention @dosu.
How did I do? Good | Irrelevant | Incorrect | Verbose | Hallucination | Report 🐛 | Other
ha I see. I now get this, when I let google use chainlit oauth callback . What might cause this? I mean, I first authenticate with google so it should work.
{"detail":"Unauthorized"}
The "Unauthorized" error after the Google OAuth flow in Chainlit is most often caused by a misconfiguration or missing environment variables—especially the OAuth client ID, client secret, or redirect URI. Chainlit reads these variables only at startup, so if you set or change them, you must fully restart the Chainlit process for the changes to take effect. If the client ID is missing or not set, the OAuth URL will have "None" as the client ID, which causes the provider to reject the login and results in this error. Also, make sure CHAINLIT_ROOT_PATH is set correctly, as an incorrect value can break the callback URL and authentication flow. Double-check your environment variables, confirm they're set before starting Chainlit, and review your server logs for more details on the failure. More details and similar issues are discussed here: example 1, example 2, example 3.
To reply, just mention @dosu.
How did I do? Good | Irrelevant | Incorrect | Verbose | Hallucination | Report 🐛 | Other
Probably related to #2309
@umeshrajanna if you found a way to do this, can you share an example how to get this setup working?
also running into this problem!
same here! any solution or workaround ?
Lots of issues related to header_auth_callback. The user session is never ready and my custom authorization token is never set. I tried replacing it with simple password auth hook and it works. I'm considering dropping Chainlit, it's becoming a nightmare to maintain. Some other similar issues are closed without a solution... I'm disappointed.
This issue is stale because it has been open for 14 days with no activity.
I can confirm the issue exists and need to be investigated
Lots of issues related to header_auth_callback. The user session is never ready and my custom authorization token is never set. I tried replacing it with simple password auth hook and it works. I'm considering dropping Chainlit, it's becoming a nightmare to maintain. Some other similar issues are closed without a solution... I'm disappointed.
Can you elaborate how this works? I am stuck on the auth header problem and need a solution
@hayescode Do you have any idea why it was closed even while it had activity and was explicitly marked as keep-for-while?
@asvishnyakov looks like dosubot closed this one
@asvishnyakov the same reason all closed issues are close, anything but having a clear solution
@1hemmem As a maintainer of a now community-maintained project, I’m very glad to hear that kind of feedback
I am able to call the @cl.header_auth_callback , my client does this, it adds a custom test header key and value but the chainlit callback does not show the key, it only has default headers. I have also set the env key os.environ["CHAINLIT_CUSTOM_AUTH"] ="True". What am I missing?
headers = {'test-header':'test-value'} url = "http://localhost:8000" response = requests.get(headers=headers, url=url,allow_redirects=True)
I tried to call http://localhost:8000/auth/header via curl:
curl -v -X POST \
-H "Content-Type: application/json" \
-H "x-auth-token: super-secret" \
-H "test-header: test-value" \
-d '{"msg": "Hello"}' \
http://localhost:8000/auth/header
and this is my callback
@cl.header_auth_callback
def header_auth_callback(headers: Dict) -> Optional[cl.User]:
# Verify the signature of a token in the header (ex: jwt token)
# or check that the value is matching a row from your database
if headers.get("test-header") == "test-value":
return cl.User(identifier="admin", metadata={"role": "admin", "provider": "header"})
else:
return None
response:
< HTTP/1.1 200 OK
< date: Tue, 28 Oct 2025 20:48:08 GMT
< server: uvicorn
< content-length: 16
< content-type: application/json
< set-cookie: access_token=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpZGVudGlmaWVyIjoiYWRtaW4iLCJkaXNwbGF5X25hbWUiOm51bGwsIm1ldGFkYXRhIjp7InJvbGUiOiJhZG1pbiIsInByb3ZpZGVyIjoiaGVhZGVyIn0sImV4cCI6MTc2Mjk4MDUwMSwiaWF0IjoxNzYxNjg0NTAxfQ.GJKhv0FNPZNIhel1jKZTUu7Maph4_m1GUiAZ_rIpBZE; HttpOnly; Max-Age=1296000; Path=/; SameSite=lax
In the debugger I can see the custom header I send.
I did not set CHAINLIT_CUSTOM_AUTH, only CHAINLIT_AUTH_SECRET since this code shows, that you can activate the custom auth by only using header_auth_callback in your code.
Hope that helps or did I misunderstood smth?