jockerz / Starlette-Login

User session management for Starlette
https://starlette-login.readthedocs.io
MIT License
11 stars 2 forks source link

Update to work with more recent starlette versions #4

Open abingham opened 1 month ago

abingham commented 1 month ago

I'm running into problems that seem to come from changes in starlette. I'm using starlette 0.37.2 and starlette-login 0.2.1.

What I see is that starlette's authentication middleware doesn't like the return result from SessionAuthBackend.authenticate(). Here's a partial stack trace:

File "/Users/austin/.virtualenvs/tubetrain-webapp-dev/lib/python3.12/site-packages/starlette/applications.py", line 123, in __call__
    await self.middleware_stack(scope, receive, send)
  File "/Users/austin/.virtualenvs/tubetrain-webapp-dev/lib/python3.12/site-packages/starlette/middleware/errors.py", line 186, in __call__
    raise exc
  File "/Users/austin/.virtualenvs/tubetrain-webapp-dev/lib/python3.12/site-packages/starlette/middleware/errors.py", line 164, in __call__
    await self.app(scope, receive, _send)
  File "/Users/austin/.virtualenvs/tubetrain-webapp-dev/lib/python3.12/site-packages/starlette/middleware/sessions.py", line 85, in __call__
    await self.app(scope, receive, send_wrapper)
  File "/Users/austin/.virtualenvs/tubetrain-webapp-dev/lib/python3.12/site-packages/starlette/middleware/authentication.py", line 48, in __call__
    scope["auth"], scope["user"] = auth_result
    ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
TypeError: cannot unpack non-iterable User object

The return value from SessionAuthBackend.authenticate() is the UserMixin subclass I've created. But starlette wants to unpack it as a sequence with two elements. So my guess is that this unpacking is a new thing representing some change in the starlette API.

First, am I diagnosing this correctly, or am I making a mistake somewhere else?

Second, if I'm diagnosing this correctly, do you have any plans to upgrade to more recent starlette versions?

abingham commented 1 month ago

It looks like the relevant issue is that AuthenticationBackend.authenticate() needs to return a tuple of [AuthCredentials, BaseUser].

abingham commented 1 month ago

On further investigation, it seems that I can just return that [AuthCredentials, BaseUser] tuple from my user-loader callable. When I do this, everything seems to work.

Is this actually OK to do? Is there any other part of starlette-login that uses the user-loader?

If doing this is OK, then the documentation should be updated to reflect it.

jockerz commented 1 month ago

Hi @abingham. Thank you for pointing this issue. I will look into it as soon as possible and inform the update of it.

jockerz commented 3 weeks ago

Hi @abingham. I still working on the issue.

Btw, Do you use starlette_login AuthenticationMiddleware?

the import is from starlette_login.middleware import AuthenticationMiddleware.

Here is the usage example:

from starlette.middleware.sessions import SessionMiddleware
from starlette_login.backends import SessionAuthBackend

from starlette_login.middleware import AuthenticationMiddleware

app = Starlette(
    middleware=[
        Middleware(SessionMiddleware, secret_key='secret'),    # required
        Middleware(
            AuthenticationMiddleware,
            ...
        )
    ],
    ...
)

The complete example is on the documentation

abingham commented 3 weeks ago

Yes, we're using AuthenticationMiddleware.