Skip to content

question/need help: how to handle "LogtoException: Invalid state in the callback URI" #33

Open
@humpydonkey

Description

@humpydonkey

Describe the bug

I'm integrating logto cloud into my fastapi service with testing/development tenant.
I have seen this exception a few times while i was testing logto sign in flow:

logto.LogtoException.LogtoException: Invalid state in the callback URI

It doesn't happen consistently. I suspect it's due to multiple concurrent calls like below occurred causing it, but i'm not sure. I saw two calls like below.

https://auth.vid-craft.com/oidc/auth?client_id=87t2l9siglorrxfcslsgl&redirect_uri=http%3A%2F%2Flocalhost%3A8000%2Fapi%2Fv1%2Fauth%2Fcallback&response_type=code&scope=openid+profile+email+phone+openid+offline_access+profile&prompt=consent&code_challenge=5QI8ErAmmqx0nBuEoMD318aZbjOsJJvB-TF7hpsD5VM&code_challenge_method=S256&state=LSoyZ3SvYQJfPe2vxGrMp9OnfBvJMVG0aCNk-sK5BlY&interaction_mode=signUp

Expected behavior

This may not be a bug, it's more of a question/asking for help.
My questions are:

  1. why does it happen? what's the root cause?
  2. how to handle this kind of exception in the server side?

How to reproduce?

The call that failed looks like below from my Chrome developer tool:

http://localhost:8000/api/v1/auth/callback?code=KdfejSLR7se2JBZeRgRutT8fp5BpFe38WITmx1AwJQM&state=5Aq2ukAcE-4m94UNT-XSeKvYYyjX5GzV1kAszXE0ylM&iss=https%3A%2F%2Fauth.vid-craft.com%2Foidc

Context

INFO:     127.0.0.1:53296 - "GET /api/v1/auth/callback?code=KdfejSLR7se2JBZeRgRutT8fp5BpFe38WITmx1AwJQM&state=5Aq2ukAcE-4m94UNT-XSeKvYYyjX5GzV1kAszXE0ylM&iss=https%3A%2F%2Fauth.vid-craft.com%2Foidc HTTP/1.1" 500 Internal Server Error
ERROR:    Exception in ASGI application
  + Exception Group Traceback (most recent call last):
  |   File "/Users/asia/work/vid_craft/backend/.venv/lib/python3.12/site-packages/starlette/_utils.py", line 77, in collapse_excgroups
  |     yield
  |   File "/Users/asia/work/vid_craft/backend/.venv/lib/python3.12/site-packages/starlette/middleware/base.py", line 186, in __call__
  |     async with anyio.create_task_group() as task_group:
  |                ^^^^^^^^^^^^^^^^^^^^^^^^^
  |   File "/Users/asia/work/vid_craft/backend/.venv/lib/python3.12/site-packages/anyio/_backends/_asyncio.py", line 736, in __aexit__
  |     raise BaseExceptionGroup(
  | ExceptionGroup: unhandled errors in a TaskGroup (1 sub-exception)
  +-+---------------- 1 ----------------
    | Traceback (most recent call last):
    |   File "/Users/asia/work/vid_craft/backend/.venv/lib/python3.12/site-packages/uvicorn/protocols/http/httptools_impl.py", line 401, in run_asgi
    |     result = await app(  # type: ignore[func-returns-value]
    |              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |   File "/Users/asia/work/vid_craft/backend/.venv/lib/python3.12/site-packages/uvicorn/middleware/proxy_headers.py", line 70, in __call__
    |     return await self.app(scope, receive, send)
    |            ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |   File "/Users/asia/work/vid_craft/backend/.venv/lib/python3.12/site-packages/fastapi/applications.py", line 1054, in __call__
    |     await super().__call__(scope, receive, send)
    |   File "/Users/asia/work/vid_craft/backend/.venv/lib/python3.12/site-packages/starlette/applications.py", line 113, in __call__
    |     await self.middleware_stack(scope, receive, send)
    |   File "/Users/asia/work/vid_craft/backend/.venv/lib/python3.12/site-packages/starlette/middleware/errors.py", line 187, in __call__
    |     raise exc
    |   File "/Users/asia/work/vid_craft/backend/.venv/lib/python3.12/site-packages/starlette/middleware/errors.py", line 165, in __call__
    |     await self.app(scope, receive, _send)
    |   File "/Users/asia/work/vid_craft/backend/.venv/lib/python3.12/site-packages/starlette/middleware/base.py", line 185, in __call__
    |     with collapse_excgroups():
    |          ^^^^^^^^^^^^^^^^^^^^
    |   File "/opt/homebrew/Cellar/python@3.12/3.12.7_1/Frameworks/Python.framework/Versions/3.12/lib/python3.12/contextlib.py", line 158, in __exit__
    |     self.gen.throw(value)
    |   File "/Users/asia/work/vid_craft/backend/.venv/lib/python3.12/site-packages/starlette/_utils.py", line 83, in collapse_excgroups
    |     raise exc
    |   File "/Users/asia/work/vid_craft/backend/.venv/lib/python3.12/site-packages/starlette/middleware/base.py", line 187, in __call__
    |     response = await self.dispatch_func(request, call_next)
    |                ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |   File "/Users/asia/work/vid_craft/backend/app/main.py", line 102, in monitor_worker_health
    |     response = await call_next(request)
    |                ^^^^^^^^^^^^^^^^^^^^^^^^
    |   File "/Users/asia/work/vid_craft/backend/.venv/lib/python3.12/site-packages/starlette/middleware/base.py", line 163, in call_next
    |     raise app_exc
    |   File "/Users/asia/work/vid_craft/backend/.venv/lib/python3.12/site-packages/starlette/middleware/base.py", line 149, in coro
    |     await self.app(scope, receive_or_disconnect, send_no_error)
    |   File "/Users/asia/work/vid_craft/backend/.venv/lib/python3.12/site-packages/starlette/middleware/base.py", line 185, in __call__
    |     with collapse_excgroups():
    |          ^^^^^^^^^^^^^^^^^^^^
    |   File "/opt/homebrew/Cellar/python@3.12/3.12.7_1/Frameworks/Python.framework/Versions/3.12/lib/python3.12/contextlib.py", line 158, in __exit__
    |     self.gen.throw(value)
    |   File "/Users/asia/work/vid_craft/backend/.venv/lib/python3.12/site-packages/starlette/_utils.py", line 83, in collapse_excgroups
    |     raise exc
    |   File "/Users/asia/work/vid_craft/backend/.venv/lib/python3.12/site-packages/starlette/middleware/base.py", line 187, in __call__
    |     response = await self.dispatch_func(request, call_next)
    |                ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |   File "/Users/asia/work/vid_craft/backend/app/main.py", line 86, in dispatch
    |     response = await call_next(request)
    |                ^^^^^^^^^^^^^^^^^^^^^^^^
    |   File "/Users/asia/work/vid_craft/backend/.venv/lib/python3.12/site-packages/starlette/middleware/base.py", line 163, in call_next
    |     raise app_exc
    |   File "/Users/asia/work/vid_craft/backend/.venv/lib/python3.12/site-packages/starlette/middleware/base.py", line 149, in coro
    |     await self.app(scope, receive_or_disconnect, send_no_error)
    |   File "/Users/asia/work/vid_craft/backend/.venv/lib/python3.12/site-packages/starlette/middleware/cors.py", line 85, in __call__
    |     await self.app(scope, receive, send)
    |   File "/Users/asia/work/vid_craft/backend/.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 "/Users/asia/work/vid_craft/backend/.venv/lib/python3.12/site-packages/starlette/_exception_handler.py", line 62, in wrapped_app
    |     raise exc
    |   File "/Users/asia/work/vid_craft/backend/.venv/lib/python3.12/site-packages/starlette/_exception_handler.py", line 51, in wrapped_app
    |     await app(scope, receive, sender)
    |   File "/Users/asia/work/vid_craft/backend/.venv/lib/python3.12/site-packages/starlette/routing.py", line 715, in __call__
    |     await self.middleware_stack(scope, receive, send)
    |   File "/Users/asia/work/vid_craft/backend/.venv/lib/python3.12/site-packages/starlette/routing.py", line 735, in app
    |     await route.handle(scope, receive, send)
    |   File "/Users/asia/work/vid_craft/backend/.venv/lib/python3.12/site-packages/starlette/routing.py", line 288, in handle
    |     await self.app(scope, receive, send)
    |   File "/Users/asia/work/vid_craft/backend/.venv/lib/python3.12/site-packages/starlette/routing.py", line 76, in app
    |     await wrap_app_handling_exceptions(app, request)(scope, receive, send)
    |   File "/Users/asia/work/vid_craft/backend/.venv/lib/python3.12/site-packages/starlette/_exception_handler.py", line 62, in wrapped_app
    |     raise exc
    |   File "/Users/asia/work/vid_craft/backend/.venv/lib/python3.12/site-packages/starlette/_exception_handler.py", line 51, in wrapped_app
    |     await app(scope, receive, sender)
    |   File "/Users/asia/work/vid_craft/backend/.venv/lib/python3.12/site-packages/starlette/routing.py", line 73, in app
    |     response = await f(request)
    |                ^^^^^^^^^^^^^^^^
    |   File "/Users/asia/work/vid_craft/backend/.venv/lib/python3.12/site-packages/fastapi/routing.py", line 301, in app
    |     raw_response = await run_endpoint_function(
    |                    ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |   File "/Users/asia/work/vid_craft/backend/.venv/lib/python3.12/site-packages/fastapi/routing.py", line 212, in run_endpoint_function
    |     return await dependant.call(**values)
    |            ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |   File "/Users/asia/work/vid_craft/backend/app/api/routes/auth.py", line 23, in callback
    |     await LOGTO_CLIENT.handleSignInCallback(str(request.url))
    |   File "/Users/asia/work/vid_craft/backend/.venv/lib/python3.12/site-packages/logto/LogtoClient.py", line 377, in handleSignInCallback
    |     raise LogtoException("Invalid state in the callback URI")
    | logto.LogtoException.LogtoException: Invalid state in the callback URI
    +------------------------------------

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "/Users/asia/work/vid_craft/backend/.venv/lib/python3.12/site-packages/uvicorn/protocols/http/httptools_impl.py", line 401, in run_asgi
    result = await app(  # type: ignore[func-returns-value]
             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/Users/asia/work/vid_craft/backend/.venv/lib/python3.12/site-packages/uvicorn/middleware/proxy_headers.py", line 70, in __call__
    return await self.app(scope, receive, send)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/Users/asia/work/vid_craft/backend/.venv/lib/python3.12/site-packages/fastapi/applications.py", line 1054, in __call__
    await super().__call__(scope, receive, send)
  File "/Users/asia/work/vid_craft/backend/.venv/lib/python3.12/site-packages/starlette/applications.py", line 113, in __call__
    await self.middleware_stack(scope, receive, send)
  File "/Users/asia/work/vid_craft/backend/.venv/lib/python3.12/site-packages/starlette/middleware/errors.py", line 187, in __call__
    raise exc
  File "/Users/asia/work/vid_craft/backend/.venv/lib/python3.12/site-packages/starlette/middleware/errors.py", line 165, in __call__
    await self.app(scope, receive, _send)
  File "/Users/asia/work/vid_craft/backend/.venv/lib/python3.12/site-packages/starlette/middleware/base.py", line 185, in __call__
    with collapse_excgroups():
         ^^^^^^^^^^^^^^^^^^^^
  File "/opt/homebrew/Cellar/python@3.12/3.12.7_1/Frameworks/Python.framework/Versions/3.12/lib/python3.12/contextlib.py", line 158, in __exit__
    self.gen.throw(value)
  File "/Users/asia/work/vid_craft/backend/.venv/lib/python3.12/site-packages/starlette/_utils.py", line 83, in collapse_excgroups
    raise exc
  File "/Users/asia/work/vid_craft/backend/.venv/lib/python3.12/site-packages/starlette/middleware/base.py", line 187, in __call__
    response = await self.dispatch_func(request, call_next)
               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/Users/asia/work/vid_craft/backend/app/main.py", line 102, in monitor_worker_health
    response = await call_next(request)
               ^^^^^^^^^^^^^^^^^^^^^^^^
  File "/Users/asia/work/vid_craft/backend/.venv/lib/python3.12/site-packages/starlette/middleware/base.py", line 163, in call_next
    raise app_exc
  File "/Users/asia/work/vid_craft/backend/.venv/lib/python3.12/site-packages/starlette/middleware/base.py", line 149, in coro
    await self.app(scope, receive_or_disconnect, send_no_error)
  File "/Users/asia/work/vid_craft/backend/.venv/lib/python3.12/site-packages/starlette/middleware/base.py", line 185, in __call__
    with collapse_excgroups():
         ^^^^^^^^^^^^^^^^^^^^
  File "/opt/homebrew/Cellar/python@3.12/3.12.7_1/Frameworks/Python.framework/Versions/3.12/lib/python3.12/contextlib.py", line 158, in __exit__
    self.gen.throw(value)
  File "/Users/asia/work/vid_craft/backend/.venv/lib/python3.12/site-packages/starlette/_utils.py", line 83, in collapse_excgroups
    raise exc
  File "/Users/asia/work/vid_craft/backend/.venv/lib/python3.12/site-packages/starlette/middleware/base.py", line 187, in __call__
    response = await self.dispatch_func(request, call_next)
               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/Users/asia/work/vid_craft/backend/app/main.py", line 86, in dispatch
    response = await call_next(request)
               ^^^^^^^^^^^^^^^^^^^^^^^^
  File "/Users/asia/work/vid_craft/backend/.venv/lib/python3.12/site-packages/starlette/middleware/base.py", line 163, in call_next
    raise app_exc
  File "/Users/asia/work/vid_craft/backend/.venv/lib/python3.12/site-packages/starlette/middleware/base.py", line 149, in coro
    await self.app(scope, receive_or_disconnect, send_no_error)
  File "/Users/asia/work/vid_craft/backend/.venv/lib/python3.12/site-packages/starlette/middleware/cors.py", line 85, in __call__
    await self.app(scope, receive, send)
  File "/Users/asia/work/vid_craft/backend/.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 "/Users/asia/work/vid_craft/backend/.venv/lib/python3.12/site-packages/starlette/_exception_handler.py", line 62, in wrapped_app
    raise exc
  File "/Users/asia/work/vid_craft/backend/.venv/lib/python3.12/site-packages/starlette/_exception_handler.py", line 51, in wrapped_app
    await app(scope, receive, sender)
  File "/Users/asia/work/vid_craft/backend/.venv/lib/python3.12/site-packages/starlette/routing.py", line 715, in __call__
    await self.middleware_stack(scope, receive, send)
  File "/Users/asia/work/vid_craft/backend/.venv/lib/python3.12/site-packages/starlette/routing.py", line 735, in app
    await route.handle(scope, receive, send)
  File "/Users/asia/work/vid_craft/backend/.venv/lib/python3.12/site-packages/starlette/routing.py", line 288, in handle
    await self.app(scope, receive, send)
  File "/Users/asia/work/vid_craft/backend/.venv/lib/python3.12/site-packages/starlette/routing.py", line 76, in app
    await wrap_app_handling_exceptions(app, request)(scope, receive, send)
  File "/Users/asia/work/vid_craft/backend/.venv/lib/python3.12/site-packages/starlette/_exception_handler.py", line 62, in wrapped_app
    raise exc
  File "/Users/asia/work/vid_craft/backend/.venv/lib/python3.12/site-packages/starlette/_exception_handler.py", line 51, in wrapped_app
    await app(scope, receive, sender)
  File "/Users/asia/work/vid_craft/backend/.venv/lib/python3.12/site-packages/starlette/routing.py", line 73, in app
    response = await f(request)
               ^^^^^^^^^^^^^^^^
  File "/Users/asia/work/vid_craft/backend/.venv/lib/python3.12/site-packages/fastapi/routing.py", line 301, in app
    raw_response = await run_endpoint_function(
                   ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/Users/asia/work/vid_craft/backend/.venv/lib/python3.12/site-packages/fastapi/routing.py", line 212, in run_endpoint_function
    return await dependant.call(**values)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/Users/asia/work/vid_craft/backend/app/api/routes/auth.py", line 23, in callback
    await LOGTO_CLIENT.handleSignInCallback(str(request.url))
  File "/Users/asia/work/vid_craft/backend/.venv/lib/python3.12/site-packages/logto/LogtoClient.py", line 377, in handleSignInCallback
    raise LogtoException("Invalid state in the callback URI")
logto.LogtoException.LogtoException: Invalid state in the callback URI
  • Logto Cloud
  • Self-hosted, Logto version =
    • Container (Docker image)
    • Raw Node.js

Screenshots

Activity

darcyYe

darcyYe commented on Jan 17, 2025

@darcyYe
Contributor

If you are receiving multiple /callback requests on the front end, there must be an issue with the code implementation.

In the /callback process, we validate the state stored in sessionStorage. Upon successful validation, we retrieve the access token and clear the sessionStorage. This results in subsequent /callback requests inevitably failing, as the state cannot be retrieved from sessionStorage for comparison. Please refer to the authorization code flow for a deeper understanding of the process.

If you can provide a code repo with your implementation that result in this error message, that can help us locate the issue.

self-assigned this
on Jan 17, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Labels

bugSomething isn't working

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

    Development

    No branches or pull requests

      Participants

      @humpydonkey@darcyYe

      Issue actions

        question/need help: how to handle "LogtoException: Invalid state in the callback URI" · Issue #33 · logto-io/python