Chainlit / chainlit

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

[Azure AD OAuth] Redirect callback URL is http://, not https:// #430

Closed wxp16 closed 11 months ago

wxp16 commented 11 months ago

image

Per the documentation, I set the callback URL as : BASE_URL/auth/oauth/azure-ad/callback. My BASE_URL is https://pre-prodxxxx. When I login, got the above error

Does anybody have any clue about this? Thanks

willydouhard commented 11 months ago

Are you sure the redirect URI is matching EXACTLY the uri of your deployed chainlit app? Including the protocol (I see you use HTTP here)?

wxp16 commented 11 months ago

My BASE URL is https://xxx and I have put https://xxx/auth/oauth/azure-ad/callback into the redirect URLs list. Why the chainlit changes the redirect URL as http://xxx ?

wxp16 commented 11 months ago

hi @willydouhard , I think here might be the root cause. When your URL uses SSL, Fastapi's Request may still get "http://xxx" https://github.com/Chainlit/chainlit/blob/aae67be728de3ebdf86e0f9ea010ae19eef9fb03/backend/chainlit/server.py#L343

willydouhard commented 11 months ago

Are you using a reverse proxy @wxp16? If that is the case here is what gpt4 says:

The issue you're facing is likely due to the request.url object in FastAPI not being aware of the scheme (http or https) used in the original request. This can happen when your FastAPI application is behind a reverse proxy (like Nginx or Apache) that handles SSL termination.

To fix this, you need to make sure that your reverse proxy is forwarding the original scheme and host to your FastAPI application. This is usually done by setting specific headers in the reverse proxy configuration.

For Nginx, you can add these lines inside your location block:

proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;

For Apache, you can add these lines inside your VirtualHost block:

RequestHeader set X-Forwarded-Proto expr=%{REQUEST_SCHEME}
RequestHeader set X-Forwarded-Host expr=%{HTTP_HOST}

Then, in your FastAPI application, you need to use a middleware that can handle these headers. FastAPI provides the TrustedHostMiddleware for this purpose:

from fastapi import FastAPI
from starlette.middleware.trustedhost import TrustedHostMiddleware

app = FastAPI()

app.add_middleware(
    TrustedHostMiddleware, allowed_hosts=["yourdomain.com"], except_path=["/health"]
)

This middleware will ensure that the request.url object correctly reflects the original scheme and host used in the request.

Please replace "yourdomain.com" with your actual domain. The except_path parameter is optional and can be used to exclude certain paths from the host validation.

wxp16 commented 11 months ago

The chainlit app was deployed in GCP's cloudrun whihc is a https endpoint. Not sure how to apply the above mentioned method into chainlit app

willydouhard commented 11 months ago

I deployed a simple app on cloud run and I was able to reproduce with google oauth. This is not only affecting Azure AD. The good thing is that it is consistently failing so debuggable. Will work on that!

Screenshot 2023-09-28 at 11 51 45
wxp16 commented 11 months ago

yeah.. same error as mine. Google provides SSL for the endpoint deployed in CloudRun. So the service endpoint starts with https://xxx . Can we fix this by replacing http:// with https:// in line 343 in file server.py

willydouhard commented 11 months ago

I dont think hardcoding it to https or automatically replacing it is a good idea. We are investigating and will release a fix tomorrow!

willydouhard commented 11 months ago

Just opened #436 to fix this. Basically for setups with reverse proxies (like cloud run) you will have to set the base url of your app (including the protocol) in the chainlit config.

Deployed this app https://chainlit-gcp-image-4xa6hnm6sq-ew.a.run.app/ on cloud run with this fix, seems to work (I did not setup Azure AD correctly but google works)

wxp16 commented 11 months ago

sounds great.

Just opened #436 to fix this. Basically for setups with reverse proxies (like cloud run) you will have to set the base url of your app (including the protocol) in the chainlit config.

Deployed this app https://chainlit-gcp-image-4xa6hnm6sq-ew.a.run.app/ on cloud run with this fix, seems to work (I did not setup Azure AD correctly but google works)

Sounds great. should work for Azure AD too. I want to try Azure Ad Oauth from my end. How to install chainlit from main branch? BTW, when are you going to release this fix to a new version?

willydouhard commented 11 months ago

Should be fixed with the 0.7.1 version. Set the base_url field in your config.toml file like so

[UI]
# If the app is served behind a reverse proxy (like cloud run) we need to know the base url for oauth
base_url = "https://mydomain.com"
wxp16 commented 11 months ago

thanks @willydouhard . After installing the new version, the redirect url is correct. But I still get socket.gaierror: [Errno -2] Name or service not known Would you mind sharing the content of /etc/resolv.conf

 "/usr/local/lib/python3.10/socket.py", line 955, in getaddrinfo for res in _socket.getaddrinfo(host, port, family, type, proto, flags): socket.gaierror: [Errno -2] Name or service not known
wxp16 commented 11 months ago

thanks @willydouhard . After installing the new version, the redirect url is correct. But I still get socket.gaierror: [Errno -2] Name or service not known Would you mind sharing the content of /etc/resolv.conf

"/usr/local/lib/python3.10/socket.py", line 955, in getaddrinfo for res in _socket.getaddrinfo(host, port, family, type, proto, flags): socket.gaierror: [Errno -2] Name or service not known

I think I know why. The aiohttp package doesn't load proxy setting from environmental variables. Though I set proxy, but still got the above error. Check here: https://github.com/aio-libs/aiohttp/issues/529 I can reproduce the error using the following code.

import aiohttp
import asyncio
async def get_response_using_proxy():
    async with aiohttp.ClientSession() as session:
        async with session.get(
            "https://login.microsoftonline.com",
        ) as response:
            print("Status Code:", response.status)
            print("Body: ", await response.text())

loop_obj = asyncio.get_event_loop()
loop_obj.run_until_complete(get_response_using_proxy())

To make the above error disappear, just use session.get( "https://login.microsoftonline.com", proxy="XXXXX", )

wxp16 commented 11 months ago

@willydouhard To validate the above mentioned error is a real bug, can u deploy an app behind an enterprise proxy and reprodce the socket.gaierror: error at your end? Thanks

willydouhard commented 11 months ago

I opened this https://github.com/Chainlit/chainlit/pull/439/files. It only change one file. Can you try to copy the new content of the file in your local installation and try again?

wxp16 commented 11 months ago

I opened this https://github.com/Chainlit/chainlit/pull/439/files. It only change one file. Can you try to copy the new content of the file in your local installation and try again?

Thanks for your quick fix. I can try from my end.

wxp16 commented 11 months ago

Hi @willydouhard . thanks. It works. I can finally login.. thanks again for your quick fix :thumbsup: pls let me know when a new verion is realsed for this fix .

image

willydouhard commented 11 months ago

Probably this week! Thank you for your feedback and patience 💯

Aux-Enderle commented 7 months ago

This solution is unsuitable for scenarios involving multiple distinct subdomains because the configuration file is restricted to specifying just one URI.

willydouhard commented 7 months ago

You can fix this with the CHAINLIT_URL env var