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

Redirect URI while behind a nginx proxy #134

Open
leshravnya opened this issue Mar 7, 2024 · 8 comments
Open

Redirect URI while behind a nginx proxy #134

leshravnya opened this issue Mar 7, 2024 · 8 comments
Labels
more info needed More info is needed in order to address the issue

Comments

@leshravnya
Copy link

I am trying to deploy my app using nginx as a proxy. My fastapi app is running on http://localhost:8000 and the nginx is listening to the public IP on port 443. I have configured the redirect_uri for the login as http://localhost:8000/auth/callback. However, after authentication from the SSO server, it redirects to the http://localhost:8000/auth/callback instead of the https://domain.example.com/auth/callback.

I tried to change the auth URI from http://localhost:8000/auth/callback to https://domain.example.com/auth/callback and I get the below error in the callback. I need help in resolving this issue.

00 Internal Server Error
ERROR:    Exception in ASGI application
Traceback (most recent call last):
  File "/home/ubuntu/resource-management/.venv/lib/python3.12/site-packages/uvicorn/protocols/http/httptools_impl.py", line 419, in run_asgi
    result = await app(  # type: ignore[func-returns-value]
             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/home/ubuntu/resource-management/.venv/lib/python3.12/site-packages/uvicorn/middleware/proxy_headers.py", line 84, in __call__
    return await self.app(scope, receive, send)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/home/ubuntu/resource-management/.venv/lib/python3.12/site-packages/fastapi/applications.py", line 1054, in __call__
    await super().__call__(scope, receive, send)
  File "/home/ubuntu/resource-management/.venv/lib/python3.12/site-packages/starlette/applications.py", line 123, in __call__
    await self.middleware_stack(scope, receive, send)
  File "/home/ubuntu/resource-management/.venv/lib/python3.12/site-packages/starlette/middleware/errors.py", line 186, in __call__
    raise exc
  File "/home/ubuntu/resource-management/.venv/lib/python3.12/site-packages/starlette/middleware/errors.py", line 164, in __call__
    await self.app(scope, receive, _send)
  File "/home/ubuntu/resource-management/.venv/lib/python3.12/site-packages/starlette/middleware/cors.py", line 83, in __call__
    await self.app(scope, receive, send)
  File "/home/ubuntu/resource-management/.venv/lib/python3.12/site-packages/starlette/middleware/exceptions.py", line 62, in __call__
    await wrap_app_handling_exceptions(self.app, conn)(scope, receive, send)
  File "/home/ubuntu/resource-management/.venv/lib/python3.12/site-packages/starlette/_exception_handler.py", line 64, in wrapped_app
    raise exc
  File "/home/ubuntu/resource-management/.venv/lib/python3.12/site-packages/starlette/_exception_handler.py", line 53, in wrapped_app
    await app(scope, receive, sender)
  File "/home/ubuntu/resource-management/.venv/lib/python3.12/site-packages/starlette/routing.py", line 758, in __call__
    await self.middleware_stack(scope, receive, send)
  File "/home/ubuntu/resource-management/.venv/lib/python3.12/site-packages/starlette/routing.py", line 778, in app
    await route.handle(scope, receive, send)
  File "/home/ubuntu/resource-management/.venv/lib/python3.12/site-packages/starlette/routing.py", line 299, in handle
    await self.app(scope, receive, send)
  File "/home/ubuntu/resource-management/.venv/lib/python3.12/site-packages/starlette/routing.py", line 79, in app
    await wrap_app_handling_exceptions(app, request)(scope, receive, send)
  File "/home/ubuntu/resource-management/.venv/lib/python3.12/site-packages/starlette/_exception_handler.py", line 64, in wrapped_app
    raise exc
  File "/home/ubuntu/resource-management/.venv/lib/python3.12/site-packages/starlette/_exception_handler.py", line 53, in wrapped_app
    await app(scope, receive, sender)
  File "/home/ubuntu/resource-management/.venv/lib/python3.12/site-packages/starlette/routing.py", line 74, in app
    response = await func(request)
               ^^^^^^^^^^^^^^^^^^^
  File "/home/ubuntu/resource-management/.venv/lib/python3.12/site-packages/fastapi/routing.py", line 278, in app
    raw_response = await run_endpoint_function(
                   ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/home/ubuntu/resource-management/.venv/lib/python3.12/site-packages/fastapi/routing.py", line 191, in run_endpoint_function
    return await dependant.call(**values)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/home/ubuntu/resource-management/backend_app/main.py", line 138, in login_callback
    openid = await microsoft_sso.verify_and_process(request)
             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/home/ubuntu/resource-management/.venv/lib/python3.12/site-packages/fastapi_sso/sso/base.py", line 294, in verify_and_process
    return await self.process_login(
           ^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/home/ubuntu/resource-management/.venv/lib/python3.12/site-packages/fastapi_sso/sso/base.py", line 387, in process_login
    self.oauth_client.parse_request_body_response(json.dumps(content))
  File "/home/ubuntu/resource-management/.venv/lib/python3.12/site-packages/oauthlib/oauth2/rfc6749/clients/base.py", line 427, in parse_request_body_response
    self.token = parse_token_response(body, scope=scope)
                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/home/ubuntu/resource-management/.venv/lib/python3.12/site-packages/oauthlib/oauth2/rfc6749/parameters.py", line 441, in parse_token_response
    validate_token_parameters(params)
  File "/home/ubuntu/resource-management/.venv/lib/python3.12/site-packages/oauthlib/oauth2/rfc6749/parameters.py", line 448, in validate_token_parameters
    raise_from_error(params.get('error'), params)
  File "/home/ubuntu/resource-management/.venv/lib/python3.12/site-packages/oauthlib/oauth2/rfc6749/errors.py", line 399, in raise_from_error
    raise cls(**kwargs)
oauthlib.oauth2.rfc6749.errors.InvalidClientError: (invalid_client) AADSTS500112: The reply address 'http://localhost:8000/auth/callback' does not match the reply address 'https://domain.example.com/auth/callback' provided when requesting Authorization code. Trace ID: 811d0b87-c6ce-4407-acd5-050e443aa800 Correlation ID: d663ad03-3c0b-4dd3-bf73-20b11373edcb Timestamp: 2024-03-07 03:57:25Z
@tomasvotava
Copy link
Owner

Hi @leshravnya, thanks for bringing this up.

Fastapi-sso currently does not handle any X-Forwarded* headers, but startlette (and fastapi) should. Are you using request.url_for to get your redirect uri? Could you provide a code snippet?

@akimrx
Copy link
Contributor

akimrx commented Apr 3, 2024

One of the standard solutions is to let the application know which domain it is being served on. Just add to the configuration of your domain.example.com and specify it in redirect_uri param.

This solution does not require middleware, but it will not work if your application is accessible from multiple domains.

@tomasvotava tomasvotava added the more info needed More info is needed in order to address the issue label Apr 30, 2024
@adityabhattad2021
Copy link

I am also facing similar kind of issue, I am running my fastapi application in a k8s cluster and am using ingress-nginx for routing:
I tried to follow the example here: https://tomasvotava.github.io/fastapi-sso/tutorials/#a-minimal-example
But I am getting this error [auth] httpx.ConnectError: All connection attempts failed when I try to navigate to: http://<domain-name>/api/auth/google/login

Here are the relevant code files:
https://github.com/adityabhattad2021/medbot/blob/main/infra/k8s/ingress-service.yaml https://github.com/adityabhattad2021/medbot/blob/main/auth/requirements.txt https://github.com/adityabhattad2021/medbot/blob/main/auth/src/app.py https://github.com/adityabhattad2021/medbot/blob/main/auth/src/routes/login_with_google.py

Thankyou.

@tomasvotava
Copy link
Owner

Hi @adityabhattad2021, this seems weird, because httpx is used to communicate with the oauth provider (Google in your case), I am not sure this is an issue with the proxy. Could you please provide the full traceback of the error?

@pausanchezv
Copy link

pausanchezv commented May 19, 2024

I am also facing similar kind of issue, I am running my fastapi application in a k8s cluster and am using ingress-nginx for routing: I tried to follow the example here: https://tomasvotava.github.io/fastapi-sso/tutorials/#a-minimal-example But I am getting this error [auth] httpx.ConnectError: All connection attempts failed when I try to navigate to: http://<domain-name>/api/auth/google/login

Here are the relevant code files: https://github.com/adityabhattad2021/medbot/blob/main/infra/k8s/ingress-service.yaml https://github.com/adityabhattad2021/medbot/blob/main/auth/requirements.txt https://github.com/adityabhattad2021/medbot/blob/main/auth/src/app.py https://github.com/adityabhattad2021/medbot/blob/main/auth/src/routes/login_with_google.py

Thankyou.

This seems more of an issue with the setup itself. Try using a service type NodePort instead of a full Ingress if you're not using SSL. That way, you'll rapidly know if the library works, but it does. I should know cause I have similar setup and it works like charm: k8s, Traefik (instead of Nginx) and CertManager. For the record it used to work well 2 years ago when I was using Ingress Nginx. Hope it helps!

@adityabhattad2021
Copy link

Hi @adityabhattad2021, this seems weird, because httpx is used to communicate with the oauth provider (Google in your case), I am not sure this is an issue with the proxy. Could you please provide the full traceback of the error?

Here:

[auth] Traceback (most recent call last):
[auth]   File "/usr/local/lib/python3.10/site-packages/uvicorn/protocols/http/h11_impl.py", line 407, in run_asgi
[auth]     result = await app(  # type: ignore[func-returns-value]
[auth]   File "/usr/local/lib/python3.10/site-packages/uvicorn/middleware/proxy_headers.py", line 69, in __call__
[auth]     return await self.app(scope, receive, send)
[auth]   File "/usr/local/lib/python3.10/site-packages/fastapi/applications.py", line 1054, in __call__
[auth]     await super().__call__(scope, receive, send)
[auth]   File "/usr/local/lib/python3.10/site-packages/starlette/applications.py", line 123, in __call__
[auth]     await self.middleware_stack(scope, receive, send)
[auth]   File "/usr/local/lib/python3.10/site-packages/starlette/middleware/errors.py", line 186, in __call__
[auth]     raise exc
[auth]   File "/usr/local/lib/python3.10/site-packages/starlette/middleware/errors.py", line 164, in __call__
[auth]     await self.app(scope, receive, _send)
[auth]   File "/usr/local/lib/python3.10/site-packages/starlette/middleware/base.py", line 189, in __call__
[auth]     with collapse_excgroups():
[auth]   File "/usr/local/lib/python3.10/contextlib.py", line 153, in __exit__
[auth]     self.gen.throw(typ, value, traceback)
[auth]   File "/usr/local/lib/python3.10/site-packages/starlette/_utils.py", line 93, in collapse_excgroups
[auth]     raise exc
[auth]   File "/usr/local/lib/python3.10/site-packages/starlette/middleware/base.py", line 191, in __call__
[auth]     response = await self.dispatch_func(request, call_next)
[auth]   File "/app/src/app.py", line 35, in dispatch
[auth]     response = await call_next(request)
[auth]   File "/usr/local/lib/python3.10/site-packages/starlette/middleware/base.py", line 165, in call_next
[auth]     raise app_exc
[auth]   File "/usr/local/lib/python3.10/site-packages/starlette/middleware/base.py", line 151, in coro
[auth]     await self.app(scope, receive_or_disconnect, send_no_error)
[auth]   File "/usr/local/lib/python3.10/site-packages/starlette/middleware/cors.py", line 85, in __call__
[auth]     await self.app(scope, receive, send)
[auth]   File "/usr/local/lib/python3.10/site-packages/starlette/middleware/exceptions.py", line 65, in __call__
[auth]     await wrap_app_handling_exceptions(self.app, conn)(scope, receive, send)
[auth]   File "/usr/local/lib/python3.10/site-packages/starlette/_exception_handler.py", line 64, in wrapped_app
[auth]     raise exc
[auth]   File "/usr/local/lib/python3.10/site-packages/starlette/_exception_handler.py", line 53, in wrapped_app
[auth]     await app(scope, receive, sender)
[auth]   File "/usr/local/lib/python3.10/site-packages/starlette/routing.py", line 756, in __call__
[auth]     await self.middleware_stack(scope, receive, send)
[auth]   File "/usr/local/lib/python3.10/site-packages/starlette/routing.py", line 776, in app
[auth]     await route.handle(scope, receive, send)
[auth]   File "/usr/local/lib/python3.10/site-packages/starlette/routing.py", line 297, in handle
[auth]     await self.app(scope, receive, send)
[auth]   File "/usr/local/lib/python3.10/site-packages/starlette/routing.py", line 77, in app
[auth]     await wrap_app_handling_exceptions(app, request)(scope, receive, send)
[auth]   File "/usr/local/lib/python3.10/site-packages/starlette/_exception_handler.py", line 64, in wrapped_app
[auth]     raise exc
[auth]   File "/usr/local/lib/python3.10/site-packages/starlette/_exception_handler.py", line 53, in wrapped_app
[auth]     await app(scope, receive, sender)
[auth]   File "/usr/local/lib/python3.10/site-packages/starlette/routing.py", line 72, in app
[auth]     response = await func(request)
[auth]   File "/usr/local/lib/python3.10/site-packages/fastapi/routing.py", line 278, in app
[auth]     raw_response = await run_endpoint_function(
[auth]   File "/usr/local/lib/python3.10/site-packages/fastapi/routing.py", line 191, in run_endpoint_function
[auth]     return await dependant.call(**values)
[auth]   File "/app/src/routes/login_with_google.py", line 32, in callback
[auth]     user = await google_sso.verify_and_process(request)
[auth]   File "/usr/local/lib/python3.10/site-packages/fastapi_sso/sso/base.py", line 359, in verify_and_process
[auth]     return await self.process_login(
[auth]   File "/usr/local/lib/python3.10/site-packages/fastapi_sso/sso/base.py", line 494, in process_login
[auth]     response = await session.post(token_url, headers=headers, content=body, auth=auth)
[auth]   File "/usr/local/lib/python3.10/site-packages/httpx/_client.py", line 1892, in post
[auth]     return await self.request(
[auth]   File "/usr/local/lib/python3.10/site-packages/httpx/_client.py", line 1574, in request
[auth]     return await self.send(request, auth=auth, follow_redirects=follow_redirects)
[auth]   File "/usr/local/lib/python3.10/site-packages/httpx/_client.py", line 1661, in send
[auth]     response = await self._send_handling_auth(
[auth]   File "/usr/local/lib/python3.10/site-packages/httpx/_client.py", line 1689, in _send_handling_auth
[auth]     response = await self._send_handling_redirects(
[auth]   File "/usr/local/lib/python3.10/site-packages/httpx/_client.py", line 1726, in _send_handling_redirects
[auth]     response = await self._send_single_request(request)
[auth]   File "/usr/local/lib/python3.10/site-packages/httpx/_client.py", line 1763, in _send_single_request
[auth]     response = await transport.handle_async_request(request)
[auth]   File "/usr/local/lib/python3.10/site-packages/httpx/_transports/default.py", line 372, in handle_async_request
[auth]     with map_httpcore_exceptions():
[auth]   File "/usr/local/lib/python3.10/contextlib.py", line 153, in __exit__
[auth]     self.gen.throw(typ, value, traceback)
[auth]   File "/usr/local/lib/python3.10/site-packages/httpx/_transports/default.py", line 86, in map_httpcore_exceptions
[auth]     raise mapped_exc(message) from exc
[auth] httpx.ConnectError: All connection attempts failed

@tomasvotava
Copy link
Owner

This is really weird, it seems more like a network trouble, are you sure the requests can go through and are not blocked on egress?

@adityabhattad2021
Copy link

Yes the requests do go through, I even tried to log those as well using this middleware

class LoggingMiddleware(BaseHTTPMiddleware):
    async def dispatch(self, request: Request, call_next):
        body = await request.body()
        print(f"Request body: {body.decode()}")
        print(f"Request headers: {dict(request.headers)}")
        print(f"Request path: {request.url.path}")
        response = await call_next(request)
        print(f"Response status: {response.status_code}")
        return response

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
more info needed More info is needed in order to address the issue
Projects
None yet
Development

No branches or pull requests

5 participants