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

bug: Python SDK with Django session async issue #22

Open
liam-pulsation opened this issue Feb 14, 2024 · 0 comments
Open

bug: Python SDK with Django session async issue #22

liam-pulsation opened this issue Feb 14, 2024 · 0 comments
Labels
bug Something isn't working

Comments

@liam-pulsation
Copy link

Python SDK with Django session async issue

Having recently discovered logto.io, we tried to implement it in Django.

We tried using TraditionalWebApp process to protect our views, following your official Flask example.

Implementation

First, I implemented /signin and /callback routes as shown in the tutorial, wrapping the logto package logic with async_to_sync decorators.

To follow the tutorial, I used session out of views using Django ref : https://docs.djangoproject.com/en/5.0/topics/http/sessions/#using-sessions-out-of-views

views.py

from logto import LogtoClient, LogtoConfig, Storage

import os
from django.views import View
from django.http import HttpResponse, HttpResponseRedirect

from importlib import import_module
from django.conf import settings

SessionStore = import_module(settings.SESSION_ENGINE).SessionStore
session = SessionStore()


class SessionStorage(Storage):
    def __init__(self):
        pass

    def get(self, key: str):
        return session.get(key, "")

    def set(self, key: str, value: str | None) -> None:
        session[key] = value

    def delete(self, key: str) -> None:
        if key in session:
            session.__delitem__(key)


client = LogtoClient(
    LogtoConfig(
        endpoint=os.environ.get("LOGTO_API_ENDPOINT"),
        appId=os.environ.get("LOGTO_API_CLIENT_ID"),
        appSecret=os.environ.get("LOGTO_API_SECRET"),
    ),
    storage=SessionStorage(),
)


class SigninView(View):
    async def get(self, request):
        uri = os.environ.get("LOGTO_API_REDIRECT_URI")
        url = await client.signIn(redirectUri=uri)
        return HttpResponseRedirect(redirect_to=url)


class CallbackView(View):
    async def get(self, request):
        absolute_uri = request.build_absolute_uri()
        try:
            await client.handleSignInCallback(absolute_uri)
            return HttpResponseRedirect(
                redirect_to=os.environ.get("LOGTO_CALLBACK_URI")
            )
        except Exception as e:
            return HttpResponse("Error: " + str(e))

urls.py

from django.urls import path

from logto_authentication.views import SigninView, CallbackView

urlpatterns = [
    path("signin/", SigninView.as_view(), name="signin"),
    path("callback/", CallbackView.as_view(), name="callback"),
]

Problem

As soon as synchronous code considered "critical" by Django (database operations with DjangoORM for the most part) is used during an asynchronous code cycle, Django will raise a SynchronousOnlyOperation: You cannot call this from an async context - use a thread or sync_to_async error.

Reference on this error : https://docs.djangoproject.com/en/5.0/topics/async/#async-safety

At that point, in the reference, we had option to set the settings to DJANGO_ALLOW_ASYNC_UNSAFE=True. Doing so make the whole process to work. But this poses a problem, as this deactivated barrier can cause data loss or corruption on other async.

Another option would have been to turn Storage synchronous calls to the session into asynchronous calls to the methods that require them. But your client is not adapted for using async methods inside this class, and we would need to create a new LogtoClient to do so.

settings.py

import os

os.environ["DJANGO_ALLOW_ASYNC_UNSAFE"] = "true"

Therefore, my question is : did anyone try TraditionalWebApp process with Django ? Did you find a way to make it work ?

Thanks in advance for your insights, and thanks for all the work you already did there !

@liam-pulsation liam-pulsation added the bug Something isn't working label Feb 14, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Something isn't working
Development

No branches or pull requests

1 participant