Coder Social home page Coder Social logo

kundapanda / strawberry-django-jwt Goto Github PK

View Code? Open in Web Editor NEW

This project forked from flavors/django-graphql-jwt

38.0 38.0 14.0 1.16 MB

[UNMAINTAINED] JSON Web Token (JWT) authentication for Django with Strawberry GraphQL

License: MIT License

Python 100.00%
django django-authentication django-jwt graphql jsonwebtoken jwt jwt-authentication strawberry-graphql

strawberry-django-jwt's People

Contributors

abumalick avatar bulatshafigullin avatar deibeljc avatar dependabot[bot] avatar edouardruiz avatar fivethreeo avatar frenchtoast747 avatar fschade avatar googol7 avatar jxltom avatar klebercode avatar kozickikarol avatar kundapanda avatar lennartkerkvliet avatar mongkok avatar mr-asher avatar nerdoc avatar patryk-tech avatar sultaniman avatar tim-schilling avatar valberg avatar vshelke avatar wmai avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar

strawberry-django-jwt's Issues

[Django 4.1] RefreshToken doesn't declare an explicit app_label

When not using refresh token:

RuntimeError: Model class strawberry_django_jwt.refresh_token.models.RefreshToken doesn't declare an explicit app_label and isn't in an application in INSTALLED_APPS.

Workaround is to add strawberry_django_jwt.refresh_token regardless of using RefreshToken or not.

Channels support

I had a play around and managed to get this working at a basic level with the upcoming Channels support: strawberry-graphql/strawberry#1407

It would be great for this package to support channels. From what I understand it requires some changes to support the difference context object.

Howto - simple example of this library

Hello,

Description :

I have integrated Strawberry with django.
I would like to integrate a third party identity server such as keycloak to authenticate my user :

  • user send a query with bearer token in the header
  • Django auth backend send a request to keycloak to identify the user
  • if user is valid info.context.request user get a user object
  • user retrieves the data he expected from the query

Your library might be what i need
Do you have an example of how to use it? Which settings should I setup ?

Thank you for your help

JSONWebTokenBackend breaks when used with a DRF request

Hi,

I'm using JSONWebTokenBackend as my main Django authentication backend to serve a GraphQL API:

AUTHENTICATION_BACKENDS = [
    "strawberry_django_jwt.backends.JSONWebTokenBackend",
    "django.contrib.auth.backends.ModelBackend",
]

I'm trying to integrate Django REST Framework to also serve a REST API but when I use my DRF endpoints, the JWT backend tries to authenticate the user and breaks when trying to get the context from the request:

  ...
  File "/usr/local/lib/python3.9/site-packages/django/contrib/auth/__init__.py", line 76, in authenticate
    user = backend.authenticate(request, **credentials)
  File "/usr/local/lib/python3.9/site-packages/strawberry_django_jwt/backends.py", line 12, in authenticate
    token = get_credentials(request, **kwargs)
  File "/usr/local/lib/python3.9/site-packages/strawberry_django_jwt/utils.py", line 131, in get_credentials
    return get_token_argument(request, **kwargs) or get_http_authorization(request)
  File "/usr/local/lib/python3.9/site-packages/strawberry_django_jwt/utils.py", line 98, in get_http_authorization
    req = get_context(context)
  File "/usr/local/lib/python3.9/site-packages/strawberry_django_jwt/utils.py", line 238, in get_context
    ctx = info.context
  File "/usr/local/lib/python3.9/site-packages/rest_framework/request.py", line 418, in __getattr__
    return self.__getattribute__(attr)
AttributeError: 'Request' object has no attribute 'context'

In my case the info parameter is a DRF Request (rest_framework.request.Request).

I'm thinking that the ctx = info.context could be wrapped in a try ... except. Would it be a good solution?

I can do a quick PR if you want.

jwt token generation public api

Hey, I had to write this code for creating the correct token payload, can the library be modified to provide an appropriate public api for usecases like this?
Sorry if the language is not polite.

from strawberry_django_jwt.object_types import TokenDataType, TokenPayloadType
from strawberry_django_jwt.decorators import on_token_auth_resolve, refresh_expiration
from strawberry_django_jwt.settings import jwt_settings
from calendar import timegm
from datetime import datetime


def generate_jwt_token_payload(info: Info, user: User):
    """
    This little abomination uses strawberry_django_jwt's cursed internals to generate a token
    compatible with `strawberry_django_jwt.mutations.ObtainJSONWebToken.obtain`
    """
    payload = TokenDataType(payload=TokenPayloadType())
    payload = on_token_auth_resolve((info, user, payload))
    payload.refresh_expires_in = timegm(
        datetime.utcnow().utctimetuple()) + jwt_settings.JWT_REFRESH_EXPIRATION_DELTA.total_seconds()
    return payload

Improve tests for specific dependency versions

Currently, testing against specific dependency versions (i.e. PyJWT, strawberry-graphql) modifies the pyproject.toml file (by running poetry add ...).

This way of testing can cause inconsistencies in the pyproject.toml file which result in tighter dependency version requirements than usual. These tests should not modify the pyproject.toml file whatsoever (if possible, that is) or assure the original toml file is restored every time.

field `refreshToken` is not async safe

consider this query

obtainPayload {
    payload {
      origIat
      exp
      username
    }
    refreshExpiresIn
    # no refresh token here
    token
  }

Works fine.
But this one:

mutation obtainJWT {
  obtainPayload {
    payload {
      origIat
      exp
      username
    }
    refreshExpiresIn
    refreshToken //  <<<
    token
  }
}

gives this error

"errors": [
    {
      "message": "You cannot call this from an async context - use a thread or sync_to_async.",
      "locations": [
        {
          "line": 11,
          "column": 7
        }
      ],
    }
]

This is possibly the line.

def create_refresh_token(user, refresh_token=None):

Wrapping JWT obtain function

This is more of a help request than an issue, so I apologize if this is not the correct forum for this post.

I have a requirement to introduce additional authentication logic to an application which is already using strawberry-django-jwt for user authentication. That is, the application already include this line in its mutation schema:

token_auth = jwt_mutations.ObtainJSONWebToken.obtain

I would like to supplement this functionality by adding additional logic before and after the use of the obtain function, which would look roughly like this

# logic executed prior to authentication goes here

jwt_mutations.ObtainJSONWebToken.obtain # authenticate the user

if authentication_successful:
    # return the token data
else:
    # logic executed due to failed authentication

is something like this achievable with the strawberry-django-jwt library? Any help is appreciated.

Async view raises `SynchronousOnlyOperation` when also logged into Django admin

i.e., when you have the sessionid cookie.

The workaround is to log out of admin, or delete the sessionid cookie.

Traceback (most recent call last):
  File "/usr/local/lib/python3.8/site-packages/graphql/execution/execute.py", line 521, in execute_field
    result = resolve_fn(source, info, **args)
  File "/usr/local/lib/python3.8/site-packages/strawberry_django_plus/optimizer.py", line 573, in resolve
    ret = _next(root, info, *args, **kwargs)
  File "/usr/local/lib/python3.8/site-packages/strawberry_django_jwt/middleware.py", line 102, in resolve
    user = authenticate(request=context, **kwargs)
  File "/usr/local/lib/python3.8/site-packages/django/views/decorators/debug.py", line 42, in sensitive_variables_wrapper
    return func(*func_args, **func_kwargs)
  File "/usr/local/lib/python3.8/site-packages/django/contrib/auth/__init__.py", line 77, in authenticate
    user = backend.authenticate(request, **credentials)
  File "/usr/local/lib/python3.8/site-packages/strawberry_django_jwt/backends.py", line 11, in authenticate
    return get_user_by_token(token, request)
  File "/usr/local/lib/python3.8/site-packages/strawberry_django_jwt/shortcuts.py", line 30, in get_user_by_token
    return get_user_by_payload(payload)
  File "/usr/local/lib/python3.8/site-packages/strawberry_django_jwt/utils.py", line 169, in get_user_by_payload
    user = jwt_settings.JWT_GET_USER_BY_NATURAL_KEY_HANDLER(username)
  File "/usr/local/lib/python3.8/site-packages/strawberry_django_jwt/utils.py", line 150, in get_user_by_natural_key
    return user_model.objects.get_by_natural_key(username)
  File "/usr/local/lib/python3.8/site-packages/django/contrib/auth/base_user.py", line 46, in get_by_natural_key
    return self.get(**{self.model.USERNAME_FIELD: username})
  File "/usr/local/lib/python3.8/site-packages/django/db/models/manager.py", line 85, in manager_method
    return getattr(self.get_queryset(), name)(*args, **kwargs)
  File "/usr/local/lib/python3.8/site-packages/django/db/models/query.py", line 492, in get
    num = len(clone)
  File "/usr/local/lib/python3.8/site-packages/django/db/models/query.py", line 302, in __len__
    self._fetch_all()
  File "/usr/local/lib/python3.8/site-packages/django/db/models/query.py", line 1507, in _fetch_all
    self._result_cache = list(self._iterable_class(self))
  File "/usr/local/lib/python3.8/site-packages/django/db/models/query.py", line 57, in __iter__
    results = compiler.execute_sql(
  File "/usr/local/lib/python3.8/site-packages/django/db/models/sql/compiler.py", line 1359, in execute_sql
    cursor = self.connection.cursor()
  File "/usr/local/lib/python3.8/site-packages/django/utils/asyncio.py", line 24, in inner
    raise SynchronousOnlyOperation(message)
django.core.exceptions.SynchronousOnlyOperation: You cannot call this from an async context - use a thread or sync_to_async.

[Error in login_required decorator] How to access loggedin user's information in a resolver?

Hi,

For authenticating queries I have used the decorator @login_required on my resolver following way:

#app.py

class Query:
      user_info: UserInfo = strawberry.field(resolver=get_user_info)

#resolver.py
from strawberry_django_jwt.decorators import login_required

@login_required
def get_user_info(self, info: Info) -> UserInfo:
    response = UserInfo(...)
     print(info)
     return response

I have written a test using requests library in python that calls this query with authorization token passed via header. It successfully goes through to the resolver after authentication of the token.

The print(info) line is throwing the following error.

%d format: a number is required, not NoneType

How do we access the user who is loggedin at resolver? The information should be available in the info object right ?

@KundaPanda I tried using the latest version of the package. Can you please check and let me know what is incorrect in this flow?

Thanks.

Extend token payload

I'm trying to get custom fields into the JWT payload to make things work with Hasura. I can set a custom jwt_payload function, but I get the problem that there is a hardcoded type TokenPayloadType used everywhere which thus throws an error: __init__() got an unexpected keyword argument.

How can I extend tokens to include custom payload?

Can't use token_auth in synch context with ASGI application

I ran this with python3.9 and Django 3.2.11:

To reproduce the issue add the following to the example urls:

urlpatterns = [
    ...
    re_path(r"^sync-graphql/?$", jwt_cookie(StatusHandlingGraphQLView.as_view(schema=sync_schema))),
]

And to schema.py:

sync_schema = Schema(
    query=Query, mutation=Mutation, extensions=[JSONWebTokenMiddleware]
)

Then login as the admin demo user, browse to http://127.0.0.1:8000/sync-graphql and run the following:

mutation LoginMutation($username: String!, $password: String!) {
  tokenAuth(username: $username, password: $password) {
    token
    __typename
  }
}

{
  "password": "admin",
  "username": "admin"
}

The response will be an error:

Internal Server Error: /sync-graphql
Traceback (most recent call last):
  File "/.cache/pypoetry/virtualenvs/strawberry-django-jwt-v7-xu3xA-py3.9/lib/python3.9/site-packages/asgiref/sync.py", line 482, in thread_handler
    raise exc_info[1]
  File "/.cache/pypoetry/virtualenvs/strawberry-django-jwt-v7-xu3xA-py3.9/lib/python3.9/site-packages/django/core/handlers/exception.py", line 38, in inner
    response = await get_response(request)
  File "/.cache/pypoetry/virtualenvs/strawberry-django-jwt-v7-xu3xA-py3.9/lib/python3.9/site-packages/django/core/handlers/base.py", line 233, in _get_response_async
    response = await wrapped_callback(request, *callback_args, **callback_kwargs)
  File "/.cache/pypoetry/virtualenvs/strawberry-django-jwt-v7-xu3xA-py3.9/lib/python3.9/site-packages/asgiref/sync.py", line 444, in __call__
    ret = await asyncio.wait_for(future, timeout=None)
  File "/.pyenv/versions/3.9.9/lib/python3.9/asyncio/tasks.py", line 442, in wait_for
    return await fut
  File "/.pyenv/versions/3.9.9/lib/python3.9/concurrent/futures/thread.py", line 58, in run
    result = self.fn(*self.args, **self.kwargs)
  File "/.cache/pypoetry/virtualenvs/strawberry-django-jwt-v7-xu3xA-py3.9/lib/python3.9/site-packages/asgiref/sync.py", line 486, in thread_handler
    return func(*args, **kwargs)
  File "/Projects/django-graphql-jwt/./strawberry_django_jwt/decorators.py", line 286, in wrapped_view
    response = view_func(request, *args, **kwargs)
  File "/.cache/pypoetry/virtualenvs/strawberry-django-jwt-v7-xu3xA-py3.9/lib/python3.9/site-packages/django/views/generic/base.py", line 70, in view
    return self.dispatch(request, *args, **kwargs)
  File "/.cache/pypoetry/virtualenvs/strawberry-django-jwt-v7-xu3xA-py3.9/lib/python3.9/site-packages/django/utils/decorators.py", line 43, in _wrapper
    return bound_method(*args, **kwargs)
  File "/.cache/pypoetry/virtualenvs/strawberry-django-jwt-v7-xu3xA-py3.9/lib/python3.9/site-packages/django/views/decorators/csrf.py", line 54, in wrapped_view
    return view_func(*args, **kwargs)
  File "/.cache/pypoetry/virtualenvs/strawberry-django-jwt-v7-xu3xA-py3.9/lib/python3.9/site-packages/strawberry/django/views.py", line 162, in dispatch
    result = self.schema.execute_sync(
  File "/.cache/pypoetry/virtualenvs/strawberry-django-jwt-v7-xu3xA-py3.9/lib/python3.9/site-packages/strawberry/schema/schema.py", line 173, in execute_sync
    result = execute_sync(
  File "/.cache/pypoetry/virtualenvs/strawberry-django-jwt-v7-xu3xA-py3.9/lib/python3.9/site-packages/strawberry/schema/execute.py", line 180, in execute_sync
    ensure_future(result).cancel()
  File "/.pyenv/versions/3.9.9/lib/python3.9/asyncio/tasks.py", line 668, in ensure_future
    loop = events.get_event_loop()
  File "/.pyenv/versions/3.9.9/lib/python3.9/asyncio/events.py", line 642, in get_event_loop
    raise RuntimeError('There is no current event loop in thread %r.'
RuntimeError: There is no current event loop in thread 'ThreadPoolExecutor-0_0'.

Then when the uvicorn process is killed, the following is printed out

sys:1: RuntimeWarning: coroutine 'ExecutionContext.build_response.<locals>.build_response_async' was never awaited
RuntimeWarning: Enable tracemalloc to get the object allocation traceback
sys:1: RuntimeWarning: coroutine 'ExecutionContext.execute_operation.<locals>.await_result' was never awaited
RuntimeWarning: Enable tracemalloc to get the object allocation traceback
sys:1: RuntimeWarning: coroutine 'ExecutionContext.execute_fields_serially.<locals>.get_results' was never awaited
RuntimeWarning: Enable tracemalloc to get the object allocation traceback
sys:1: RuntimeWarning: coroutine 'ExecutionContext.execute_fields_serially.<locals>.set_result' was never awaited
RuntimeWarning: Enable tracemalloc to get the object allocation traceback
sys:1: RuntimeWarning: coroutine 'ExecutionContext.resolve_field.<locals>.await_result' was never awaited
RuntimeWarning: Enable tracemalloc to get the object allocation traceback
sys:1: RuntimeWarning: coroutine 'setup_jwt_cookie.<locals>.set_token' was never awaited
RuntimeWarning: Enable tracemalloc to get the object allocation traceback
sys:1: RuntimeWarning: coroutine 'await_and_execute.<locals>.build_resolve_async' was never awaited
RuntimeWarning: Enable tracemalloc to get the object allocation traceback
sys:1: RuntimeWarning: coroutine 'token_auth.<locals>.wrapper_async' was never awaited
RuntimeWarning: Enable tracemalloc to get the object allocation traceback

VSCode debugger not working with this library

Hello there.

Somehow I get a InvalidSignatureError error whenever I use my debugger. But I won't get it if I'm running a normal uvicorn server.

This is my launch.json:

{
    // Use IntelliSense to learn about possible attributes.
    // Hover to view descriptions of existing attributes.
    // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
    "version": "0.2.0",
    "configurations": [
        {
            "name": "Python: Current File",
            "type": "python",
            "request": "launch",
            "program": "${file}",
            "console": "integratedTerminal",
            "justMyCode": true
        },
        {
            "name": "Python: Django",
            "type": "python",
            "request": "launch",
            "module": "uvicorn",
            "args": [
                "project.asgi:application",
                "--reload",
                "--host",
                "0.0.0.0",
                "--port",
                "8000"
            ],
            "django": true,
            "env": {
                "PYTEST_ADDOPTS": "--no-cov"
            },
        }
    ]
}

This is my strawberry schema:

schema = strawberry.Schema(
    query=Query,
    mutation=Mutation,
    extensions=[
        optimizer.DjangoOptimizerExtension,
        directives.SchemaDirectiveExtension,
        AsyncJSONWebTokenMiddleware,
    ],
)

Incompatible with packaging==20.9

HI, I have another incompatibility issue with packaging<22.0,>=21.0. Can this dependency requirement be lowered to include at least packaging==20.9 version? Thank you.

GraphQL explorer disabled by this library

When I setup this library, my GraphQL explorer is no longer able to introspect my backend's schema.

The problem stops if I comment JSONWebTokenMiddleware in my schema's extensions:

schema = strawberry.Schema(
    query=Query,
    mutation=Mutation,
    extensions=[
        ...
        JSONWebTokenMiddleware # -> Comment this and in starts working again
        ...
    ],
)

It does work nonetheless:
image
It seems like the explorer is suddenly not obtaining something it's looking for:
image

This is my setup:

# settings.py
import os
from pathlib import Path


BASE_DIR = Path(__file__).resolve().parent.parent

SECRET_KEY = os.environ.get("SECRET_KEY")

DEBUG = os.environ.get("DEBUG")

ALLOWED_HOSTS = [el for el in os.environ.get("ALLOWED_HOSTS").split(",")]

INSTALLED_APPS = [
    "django.contrib.admin",
    "django.contrib.auth",
    "django.contrib.contenttypes",
    "django.contrib.sessions",
    "django.contrib.messages",
    "django.contrib.staticfiles",
    # Project apps
    "users",
    # Third party apps
    "corsheaders",
    "strawberry_django_jwt.refresh_token"
]

MIDDLEWARE = [
    "django.middleware.security.SecurityMiddleware",
    "django.contrib.sessions.middleware.SessionMiddleware",
    "corsheaders.middleware.CorsMiddleware",
    "django.middleware.common.CommonMiddleware",
    "django.middleware.csrf.CsrfViewMiddleware",
    "django.contrib.auth.middleware.AuthenticationMiddleware",
    "django.contrib.messages.middleware.MessageMiddleware",
    "django.middleware.clickjacking.XFrameOptionsMiddleware"
]

ROOT_URLCONF = "project.urls"

TEMPLATES = [
    {
        "BACKEND": "django.template.backends.django.DjangoTemplates",
        "DIRS": [],
        "APP_DIRS": True,
        "OPTIONS": {
            "context_processors": [
                "django.template.context_processors.debug",
                "django.template.context_processors.request",
                "django.contrib.auth.context_processors.auth",
                "django.contrib.messages.context_processors.messages",
            ],
        },
    },
]

WSGI_APPLICATION = "project.wsgi.application"

DATABASES = {
    "default": {
        "ENGINE": os.environ.get("SQL_ENGINE"),
        "NAME": os.environ.get("SQL_DATABASE"),
        "USER": os.environ.get("SQL_USER"),
        "PASSWORD": os.environ.get("SQL_PASSWORD"),
        "HOST": os.environ.get("SQL_HOST"),
        "PORT": os.environ.get("SQL_PORT"),
    }
}

AUTH_PASSWORD_VALIDATORS = [
    {
        "NAME": "django.contrib.auth.password_validation.UserAttributeSimilarityValidator",
    },
    {
        "NAME": "django.contrib.auth.password_validation.MinimumLengthValidator",
    },
    {
        "NAME": "django.contrib.auth.password_validation.CommonPasswordValidator",
    },
    {
        "NAME": "django.contrib.auth.password_validation.NumericPasswordValidator",
    },
]

LANGUAGE_CODE = "en-us"

TIME_ZONE = "UTC"

USE_I18N = True

USE_L10N = True

USE_TZ = True

STATIC_URL = "/static/"

AUTH_USER_MODEL = "users.CustomUser"

DEFAULT_AUTO_FIELD = "django.db.models.BigAutoField"

AUTHENTICATION_BACKENDS = [
    'strawberry_django_jwt.backends.JSONWebTokenBackend',
    'django.contrib.auth.backends.ModelBackend',
]
GRAPHQL_JWT = {"JWT_AUTHENTICATE_INTROSPECTION": True}
# urls.py
from django.conf import settings
from django.contrib import admin
from django.urls import path
from strawberry.django.views import GraphQLView

from project.schema import schema


if settings.DEBUG:
    urlpatterns = [
        path("admin/", admin.site.urls),
        path("graphql/", GraphQLView.as_view(schema=schema)),
    ]
else:
    urlpatterns = [
        # Safe urls grabbed from .env
    ]
# from typing import List
import strawberry
from strawberry_django_jwt.middleware import JSONWebTokenMiddleware
from strawberry_django_plus import directives, optimizer
from users.api import types as ut, resolvers as ur, permissions as up
import strawberry_django_jwt.mutations as jwt_mutations


@strawberry.type
class Query:
    me: ut.User = strawberry.field(
        resolver=ur.me,
        permission_classes=[up.IsAuthenticated]
    )


@strawberry.type
class Mutation:
    create_user:    ut.User         = strawberry.mutation(resolver=ur.create_user)
    login_user:     ut.LoginSuccess = strawberry.mutation(resolver=ur.login)
    logout_user:    ut.User         = strawberry.mutation(resolver=ur.logout)
    token_auth = jwt_mutations.ObtainJSONWebToken.obtain
    verify_token = jwt_mutations.Verify.verify
    refresh_token = jwt_mutations.Refresh.refresh
    delete_token_cookie = jwt_mutations.DeleteJSONWebTokenCookie.delete_cookie

schema = strawberry.Schema(
    query=Query,
    mutation=Mutation,
    extensions=[
        optimizer.DjangoOptimizerExtension,
        directives.SchemaDirectiveExtension,
        JSONWebTokenMiddleware
    ],
)
# resolvers.py
from typing import Union
from strawberry.types import Info
from strawberry_django import django_resolver
from django.contrib import auth

from project.common.utils import data_to_dict
from users import models as m
from users.api import types as t


def create_user(self, info: Info, data: t.UserInput) -> t.User:
    user_data = data_to_dict(data)
    user = m.CustomUser(**user_data)
    user.set_password(data.password)
    user.save()
    return user

def login(self, info: Info, data: t.UserInput) -> t.LoginResult:
    request = info.context.request

    user = auth.authenticate(
        request=request,
        email=data.email,
        password=data.password
    )

    if user is not None:
        auth.login(request, user)
        return t.LoginSuccess(user=user)
    auth.logout(request)
    return t.LoginError(message="Credenciales errรณneas")

def logout(self, info: Info) -> bool:
    request = info.context.request
    ret = request.user.is_authenticated
    auth.logout(request)
    return ret

def me(self, info: Info) -> t.User | None:
    user: m.CustomUser = info.context.request.user
    if user.is_authenticated:
        return user
    return None

Relax strawberry-graphql dependency requirement

Hi,

Thanks for updating strawberry-django-jwt to make it compatible with strawberry-graphql>=0.69.0. However the latest version (0.1.2) requires strawberry-graphql>=0.73.8,<0.74.0.

Would it be possible to relax this requirement to allow strawberry-graphql>=0.74.0 and further releases? strawberry-graphql seems to evolve quite fast...

Generating JWT token using shortcuts - create_refresh_token(user) throwing error

Hi,

Thank you for creating strawberry-django-jwt, we recently migrated from graphene and added this to our project.

Following is my query :

For JWT authentication the obtain token mutation requires username and password, but for social authentication we do not require the password. As the implementation is such where user information is stored during signup along with social tokens that can be verified from a database query. In graphene we have written a mutation for social login that uses social token verification and later issues a JWT token using graphql_jwt shortcut get_token(user) where a user instance was passed based on identifying the user via social token information.

Do we have something similar in strawberry-django-jwt where we can issue JWT token and send signal without the password field for authenticate ?

from graphql_jwt.shortcuts import get_token
from graphql_jwt.refresh_token.shortcuts import create_refresh_token

token = get_token(user)
refresh_token = create_refresh_token(user)

Can you help me with an example or point me to the code where we can override/customise existing functionality to achieve the above?

Custom authentication

I have a unique usecase where I want to generate a token based on an API key, and not the normal django user model. Is there an easy way to override this? I see in the decorators.py there is a block that looks like it could run an optional custom auth function that is passed in or something like that instead of the normal flow.

is token_auth mutation sync only?

I have been trying to implement an async api with strawberry. I have followed the documentation for making strawberry-django-jwt work with async, but every time I run token auth, I get the following error:

{ "data": null, "errors": [ { "message": "You cannot call this from an async context - use a thread or sync_to_async.", "locations": [ { "line": 2, "column": 2 } ], "path": [ "tokenAuth" ] } ] }

What should I do? Is it not supported or is it a bug? Thanks in advance

pyjwt>=2.1.0 dependency incompatibility issue

Thank you for this great initiative! I tried to add it to my project but encountered a dependency incompatibility issue with the required pyjwt > 2.1.0. Any chance to include previous versions (>=1.7) of this dependency in future releases?

Create new exception type for authentication errors

Currently the library raises an exception for authentication failures. I think it should be a specific exception class so it can be filtered out more easily.

In my case, I'm overriding strawberry's schema to support an ignoreable collection of exceptions. These won't be passed to the logger and thus avoid the exception handling logic. However, strawberry-django-jwt uses an exception class that's subclassed when a user enters the wrong credentials.

class Schema(strawberry.Schema):
    ignored_errors: tuple[Type[Exception]]

    def __init__(self, *args, ignored_errors=None, **kwargs):
        super().__init__(*args, **kwargs)
        self.ignored_errors = ignored_errors

    def process_errors(
        self,
        errors: List[GraphQLError],
        execution_context: Optional[ExecutionContext] = None,
    ) -> None:
        for error in errors:
            if error.original_error and self.ignored_errors and isinstance(
                error.original_error, self.ignored_errors
            ):
                continue
            StrawberryLogger.error(error, execution_context)

If it seems reasonable, I can create the PR.

Output types instead of exceptions.

Currently the JSONWebTokenMiddleware will raise an exception if i.e the token has expired.
This is graphql abusing, we should instead return an output type.
throwing exceptions should be only on real exceptions not something you expect.

This is a simple workaround to suppress the errors.

class MyAsyncJSONWebTokenMiddleware(AsyncJSONWebTokenMiddleware):
    async def resolve(self, _next, root, info: GraphQLResolveInfo, *args, **kwargs):
        try:
            return await super().resolve(_next, root, info, *args, **kwargs)
        except JSONWebTokenError:
            result = _next(root, info, **kwargs)
            if isawaitable(result):
                return await result
            return result

This issue is somewhat related to #202

RefreshTokenMixin yields ValueError

Django: 4.1
Python: 3.10.4
strawberry-django-jwt 0.2.2

I've followed the setup instructions on the README and included the optional refresh token configuration. When invoking the refreshToken mutation I run into the following error:

GraphQL request:2:3
2 |   refreshToken (token:"eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJleHAiOjE2NjMzMTE4
  |   ^
...
  File "/usr/local/lib/python3.10/site-packages/strawberry_django_jwt/mixins.py", line 107, in _refresh
    result = TokenDataType(payload, token, refresh_expires_in)
TypeError: TokenDataType.__init__() takes 1 positional argument but 4 were given

It appears this line attempts to instantiate TokenDataType using 3 positional arguments when there are 4 members:

@strawberry.type
class TokenDataType:
payload: TokenPayloadType
token: str = ""
refresh_token: Optional[str] = None
refresh_expires_in: Optional[int] = None

I think this could be resolved by changing the call to result = TokenDataType(payload=payload, token=token, refresh_expired_in=refresh_expires_in).

permission_required decorator not working

With a type definition like this:

# types.py
@type(models.User, keys=["id"], filters=UserFilter, order=UserOrder, pagination=True)
class User:
    id: auto
    username: auto
    email: auto
    first_name: auto
    last_name: auto

    @strawberry.field
    @permission_required("users.view_user")
    def permissions(self, info) -> List[str]:
        return []

I'm getting an error like this:

CollectionUsers_server | GraphQL request:1:42
CollectionUsers_server | 1 | {users{firstName lastName username email permissions}}
CollectionUsers_server |   |                                          ^
CollectionUsers_server | Traceback (most recent call last):
CollectionUsers_server |   File "/root/.local/share/virtualenvs/server-MrgTHRtU/lib/python3.8/site-packages/graphql/execution/execute.py", line 617, in resolve_field
CollectionUsers_server |     result = resolve_fn(source, info, **args)
CollectionUsers_server |   File "/root/.local/share/virtualenvs/server-MrgTHRtU/lib/python3.8/site-packages/strawberry/middleware.py", line 57, in resolve
CollectionUsers_server |     result = next_(root, info, **kwargs)
CollectionUsers_server |   File "/root/.local/share/virtualenvs/server-MrgTHRtU/lib/python3.8/site-packages/strawberry_django_jwt/middleware.py", line 92, in resolve
CollectionUsers_server |     return next_(root, info, **kwargs)
CollectionUsers_server |   File "/root/.local/share/virtualenvs/server-MrgTHRtU/lib/python3.8/site-packages/strawberry/schema/schema_converter.py", line 389, in _resolver
CollectionUsers_server |     return _get_result(_source, strawberry_info, **kwargs)
CollectionUsers_server |   File "/root/.local/share/virtualenvs/server-MrgTHRtU/lib/python3.8/site-packages/strawberry/schema/schema_converter.py", line 381, in _get_result
CollectionUsers_server |     return field.get_result(
CollectionUsers_server |   File "/root/.local/share/virtualenvs/server-MrgTHRtU/lib/python3.8/site-packages/strawberry_django/fields/field.py", line 99, in get_result
CollectionUsers_server |     return super().get_result(source, info, args, kwargs)
CollectionUsers_server |   File "/root/.local/share/virtualenvs/server-MrgTHRtU/lib/python3.8/site-packages/strawberry/field.py", line 279, in get_result
CollectionUsers_server |     return self.base_resolver(*args, **kwargs)
CollectionUsers_server |   File "/root/.local/share/virtualenvs/server-MrgTHRtU/lib/python3.8/site-packages/strawberry/types/fields/resolver.py", line 39, in __call__
CollectionUsers_server |     return self.wrapped_func(*args, **kwargs)
CollectionUsers_server |   File "/root/.local/share/virtualenvs/server-MrgTHRtU/lib/python3.8/site-packages/strawberry_django_jwt/decorators.py", line 79, in wrapper
CollectionUsers_server |     return func(ctx, *args, **kwargs)
CollectionUsers_server |   File "/root/.local/share/virtualenvs/server-MrgTHRtU/lib/python3.8/site-packages/strawberry_django_jwt/decorators.py", line 92, in wrapper
CollectionUsers_server |     return dispose_extra_kwargs(f)(*args, **kwargs)
CollectionUsers_server |   File "/root/.local/share/virtualenvs/server-MrgTHRtU/lib/python3.8/site-packages/strawberry_django_jwt/decorators.py", line 324, in wrapper
CollectionUsers_server |     return fn(src, root, *args_, **passed_kwargs)
CollectionUsers_server | TypeError: permissions() got multiple values for argument 'info'
CollectionUsers_server | Stack (most recent call last):
CollectionUsers_server |   File "/usr/lib/python3.8/threading.py", line 890, in _bootstrap
CollectionUsers_server |     self._bootstrap_inner()
CollectionUsers_server |   File "/usr/lib/python3.8/threading.py", line 932, in _bootstrap_inner
CollectionUsers_server |     self.run()
CollectionUsers_server |   File "/usr/lib/python3.8/threading.py", line 870, in run
CollectionUsers_server |     self._target(*self._args, **self._kwargs)
CollectionUsers_server |   File "/usr/lib/python3.8/socketserver.py", line 650, in process_request_thread
CollectionUsers_server |     self.finish_request(request, client_address)
CollectionUsers_server |   File "/usr/lib/python3.8/socketserver.py", line 360, in finish_request
CollectionUsers_server |     self.RequestHandlerClass(request, client_address, self)
CollectionUsers_server |   File "/usr/lib/python3.8/socketserver.py", line 720, in __init__
CollectionUsers_server |     self.handle()
CollectionUsers_server |   File "/root/.local/share/virtualenvs/server-MrgTHRtU/lib/python3.8/site-packages/django/core/servers/basehttp.py", line 176, in handle
CollectionUsers_server |     self.handle_one_request()
CollectionUsers_server |   File "/root/.local/share/virtualenvs/server-MrgTHRtU/lib/python3.8/site-packages/django/core/servers/basehttp.py", line 201, in handle_one_request
CollectionUsers_server |     handler.run(self.server.get_app())
CollectionUsers_server |   File "/usr/lib/python3.8/wsgiref/handlers.py", line 137, in run
CollectionUsers_server |     self.result = application(self.environ, self.start_response)
CollectionUsers_server |   File "/root/.local/share/virtualenvs/server-MrgTHRtU/lib/python3.8/site-packages/django/contrib/staticfiles/handlers.py", line 76, in __call__
CollectionUsers_server |     return self.application(environ, start_response)
CollectionUsers_server |   File "/root/.local/share/virtualenvs/server-MrgTHRtU/lib/python3.8/site-packages/django/core/handlers/wsgi.py", line 133, in __call__
CollectionUsers_server |     response = self.get_response(request)
CollectionUsers_server |   File "/root/.local/share/virtualenvs/server-MrgTHRtU/lib/python3.8/site-packages/django/core/handlers/base.py", line 130, in get_response
CollectionUsers_server |     response = self._middleware_chain(request)
CollectionUsers_server |   File "/root/.local/share/virtualenvs/server-MrgTHRtU/lib/python3.8/site-packages/django/core/handlers/exception.py", line 47, in inner
CollectionUsers_server |     response = get_response(request)
CollectionUsers_server |   File "/root/.local/share/virtualenvs/server-MrgTHRtU/lib/python3.8/site-packages/django/utils/deprecation.py", line 117, in __call__
CollectionUsers_server |     response = response or self.get_response(request)
CollectionUsers_server |   File "/root/.local/share/virtualenvs/server-MrgTHRtU/lib/python3.8/site-packages/django/core/handlers/exception.py", line 47, in inner
CollectionUsers_server |     response = get_response(request)
CollectionUsers_server |   File "/root/.local/share/virtualenvs/server-MrgTHRtU/lib/python3.8/site-packages/django/utils/deprecation.py", line 117, in __call__
CollectionUsers_server |     response = response or self.get_response(request)
CollectionUsers_server |   File "/root/.local/share/virtualenvs/server-MrgTHRtU/lib/python3.8/site-packages/django/core/handlers/exception.py", line 47, in inner
CollectionUsers_server |     response = get_response(request)
CollectionUsers_server |   File "/root/.local/share/virtualenvs/server-MrgTHRtU/lib/python3.8/site-packages/django/utils/deprecation.py", line 117, in __call__
CollectionUsers_server |     response = response or self.get_response(request)
CollectionUsers_server |   File "/root/.local/share/virtualenvs/server-MrgTHRtU/lib/python3.8/site-packages/django/core/handlers/exception.py", line 47, in inner
CollectionUsers_server |     response = get_response(request)
CollectionUsers_server |   File "/root/.local/share/virtualenvs/server-MrgTHRtU/lib/python3.8/site-packages/django/utils/deprecation.py", line 117, in __call__
CollectionUsers_server |     response = response or self.get_response(request)
CollectionUsers_server |   File "/root/.local/share/virtualenvs/server-MrgTHRtU/lib/python3.8/site-packages/django/core/handlers/exception.py", line 47, in inner
CollectionUsers_server |     response = get_response(request)
CollectionUsers_server |   File "/root/.local/share/virtualenvs/server-MrgTHRtU/lib/python3.8/site-packages/django/utils/deprecation.py", line 117, in __call__
CollectionUsers_server |     response = response or self.get_response(request)
CollectionUsers_server |   File "/root/.local/share/virtualenvs/server-MrgTHRtU/lib/python3.8/site-packages/django/core/handlers/exception.py", line 47, in inner
CollectionUsers_server |     response = get_response(request)
CollectionUsers_server |   File "/root/.local/share/virtualenvs/server-MrgTHRtU/lib/python3.8/site-packages/django/utils/deprecation.py", line 117, in __call__
CollectionUsers_server |     response = response or self.get_response(request)
CollectionUsers_server |   File "/root/.local/share/virtualenvs/server-MrgTHRtU/lib/python3.8/site-packages/django/core/handlers/exception.py", line 47, in inner
CollectionUsers_server |     response = get_response(request)
CollectionUsers_server |   File "/root/.local/share/virtualenvs/server-MrgTHRtU/lib/python3.8/site-packages/django/utils/deprecation.py", line 117, in __call__
CollectionUsers_server |     response = response or self.get_response(request)
CollectionUsers_server |   File "/root/.local/share/virtualenvs/server-MrgTHRtU/lib/python3.8/site-packages/django/core/handlers/exception.py", line 47, in inner
CollectionUsers_server |     response = get_response(request)
CollectionUsers_server |   File "/root/.local/share/virtualenvs/server-MrgTHRtU/lib/python3.8/site-packages/django/core/handlers/base.py", line 181, in _get_response
CollectionUsers_server |     response = wrapped_callback(request, *callback_args, **callback_kwargs)
CollectionUsers_server |   File "/root/.local/share/virtualenvs/server-MrgTHRtU/lib/python3.8/site-packages/django/views/generic/base.py", line 70, in view
CollectionUsers_server |     return self.dispatch(request, *args, **kwargs)
CollectionUsers_server |   File "/root/.local/share/virtualenvs/server-MrgTHRtU/lib/python3.8/site-packages/django/utils/decorators.py", line 43, in _wrapper
CollectionUsers_server |     return bound_method(*args, **kwargs)
CollectionUsers_server |   File "/root/.local/share/virtualenvs/server-MrgTHRtU/lib/python3.8/site-packages/django/views/decorators/csrf.py", line 54, in wrapped_view
CollectionUsers_server |     return view_func(*args, **kwargs)
CollectionUsers_server |   File "/root/.local/share/virtualenvs/server-MrgTHRtU/lib/python3.8/site-packages/strawberry/django/views.py", line 148, in dispatch
CollectionUsers_server |     result = self.schema.execute_sync(
CollectionUsers_server | [04/Oct/2021 05:09:19] "POST /graphql HTTP/1.1" 200 175
CollectionUsers_server | permissions() got multiple values for argument 'info'
CollectionUsers_server |
CollectionUsers_server | GraphQL request:1:42
CollectionUsers_server | 1 | {users{firstName lastName username email permissions}}
CollectionUsers_server |   |                                          ^
CollectionUsers_server | Traceback (most recent call last):
CollectionUsers_server |   File "/root/.local/share/virtualenvs/server-MrgTHRtU/lib/python3.8/site-packages/graphql/execution/execute.py", line 617, in resolve_field
CollectionUsers_server |     result = resolve_fn(source, info, **args)
CollectionUsers_server |   File "/root/.local/share/virtualenvs/server-MrgTHRtU/lib/python3.8/site-packages/strawberry/middleware.py", line 57, in resolve
CollectionUsers_server |     result = next_(root, info, **kwargs)
CollectionUsers_server |   File "/root/.local/share/virtualenvs/server-MrgTHRtU/lib/python3.8/site-packages/strawberry_django_jwt/middleware.py", line 92, in resolve
CollectionUsers_server |     return next_(root, info, **kwargs)
CollectionUsers_server |   File "/root/.local/share/virtualenvs/server-MrgTHRtU/lib/python3.8/site-packages/strawberry/schema/schema_converter.py", line 389, in _resolver
CollectionUsers_server |     return _get_result(_source, strawberry_info, **kwargs)
CollectionUsers_server |   File "/root/.local/share/virtualenvs/server-MrgTHRtU/lib/python3.8/site-packages/strawberry/schema/schema_converter.py", line 381, in _get_result
CollectionUsers_server |     return field.get_result(
CollectionUsers_server |   File "/root/.local/share/virtualenvs/server-MrgTHRtU/lib/python3.8/site-packages/strawberry_django/fields/field.py", line 99, in get_result
CollectionUsers_server |     return super().get_result(source, info, args, kwargs)
CollectionUsers_server |   File "/root/.local/share/virtualenvs/server-MrgTHRtU/lib/python3.8/site-packages/strawberry/field.py", line 279, in get_result
CollectionUsers_server |     return self.base_resolver(*args, **kwargs)
CollectionUsers_server |   File "/root/.local/share/virtualenvs/server-MrgTHRtU/lib/python3.8/site-packages/strawberry/types/fields/resolver.py", line 39, in __call__
CollectionUsers_server |     return self.wrapped_func(*args, **kwargs)
CollectionUsers_server |   File "/root/.local/share/virtualenvs/server-MrgTHRtU/lib/python3.8/site-packages/strawberry_django_jwt/decorators.py", line 79, in wrapper
CollectionUsers_server |     return func(ctx, *args, **kwargs)
CollectionUsers_server |   File "/root/.local/share/virtualenvs/server-MrgTHRtU/lib/python3.8/site-packages/strawberry_django_jwt/decorators.py", line 92, in wrapper
CollectionUsers_server |     return dispose_extra_kwargs(f)(*args, **kwargs)
CollectionUsers_server |   File "/root/.local/share/virtualenvs/server-MrgTHRtU/lib/python3.8/site-packages/strawberry_django_jwt/decorators.py", line 324, in wrapper
CollectionUsers_server |     return fn(src, root, *args_, **passed_kwargs)
CollectionUsers_server | TypeError: permissions() got multiple values for argument 'info'
CollectionUsers_server | Stack (most recent call last):
CollectionUsers_server |   File "/usr/lib/python3.8/threading.py", line 890, in _bootstrap
CollectionUsers_server |     self._bootstrap_inner()
CollectionUsers_server |   File "/usr/lib/python3.8/threading.py", line 932, in _bootstrap_inner
CollectionUsers_server |     self.run()
CollectionUsers_server |   File "/usr/lib/python3.8/threading.py", line 870, in run
CollectionUsers_server |     self._target(*self._args, **self._kwargs)
CollectionUsers_server |   File "/usr/lib/python3.8/socketserver.py", line 650, in process_request_thread
CollectionUsers_server |     self.finish_request(request, client_address)
CollectionUsers_server |   File "/usr/lib/python3.8/socketserver.py", line 360, in finish_request
CollectionUsers_server |     self.RequestHandlerClass(request, client_address, self)
CollectionUsers_server |   File "/usr/lib/python3.8/socketserver.py", line 720, in __init__
CollectionUsers_server |     self.handle()
CollectionUsers_server |   File "/root/.local/share/virtualenvs/server-MrgTHRtU/lib/python3.8/site-packages/django/core/servers/basehttp.py", line 176, in handle
CollectionUsers_server |     self.handle_one_request()
CollectionUsers_server |   File "/root/.local/share/virtualenvs/server-MrgTHRtU/lib/python3.8/site-packages/django/core/servers/basehttp.py", line 201, in handle_one_request
CollectionUsers_server |     handler.run(self.server.get_app())
CollectionUsers_server |   File "/usr/lib/python3.8/wsgiref/handlers.py", line 137, in run
CollectionUsers_server |     self.result = application(self.environ, self.start_response)
CollectionUsers_server |   File "/root/.local/share/virtualenvs/server-MrgTHRtU/lib/python3.8/site-packages/django/contrib/staticfiles/handlers.py", line 76, in __call__
CollectionUsers_server |     return self.application(environ, start_response)
CollectionUsers_server |   File "/root/.local/share/virtualenvs/server-MrgTHRtU/lib/python3.8/site-packages/django/core/handlers/wsgi.py", line 133, in __call__
CollectionUsers_server |     response = self.get_response(request)
CollectionUsers_server |   File "/root/.local/share/virtualenvs/server-MrgTHRtU/lib/python3.8/site-packages/django/core/handlers/base.py", line 130, in get_response
CollectionUsers_server |     response = self._middleware_chain(request)
CollectionUsers_server |   File "/root/.local/share/virtualenvs/server-MrgTHRtU/lib/python3.8/site-packages/django/core/handlers/exception.py", line 47, in inner
CollectionUsers_server |     response = get_response(request)
CollectionUsers_server |   File "/root/.local/share/virtualenvs/server-MrgTHRtU/lib/python3.8/site-packages/django/utils/deprecation.py", line 117, in __call__
CollectionUsers_server |     response = response or self.get_response(request)
CollectionUsers_server |   File "/root/.local/share/virtualenvs/server-MrgTHRtU/lib/python3.8/site-packages/django/core/handlers/exception.py", line 47, in inner
CollectionUsers_server |     response = get_response(request)
CollectionUsers_server |   File "/root/.local/share/virtualenvs/server-MrgTHRtU/lib/python3.8/site-packages/django/utils/deprecation.py", line 117, in __call__
CollectionUsers_server |     response = response or self.get_response(request)
CollectionUsers_server |   File "/root/.local/share/virtualenvs/server-MrgTHRtU/lib/python3.8/site-packages/django/core/handlers/exception.py", line 47, in inner
CollectionUsers_server |     response = get_response(request)
CollectionUsers_server |   File "/root/.local/share/virtualenvs/server-MrgTHRtU/lib/python3.8/site-packages/django/utils/deprecation.py", line 117, in __call__
CollectionUsers_server |     response = response or self.get_response(request)
CollectionUsers_server |   File "/root/.local/share/virtualenvs/server-MrgTHRtU/lib/python3.8/site-packages/django/core/handlers/exception.py", line 47, in inner
CollectionUsers_server |     response = get_response(request)
CollectionUsers_server |   File "/root/.local/share/virtualenvs/server-MrgTHRtU/lib/python3.8/site-packages/django/utils/deprecation.py", line 117, in __call__
CollectionUsers_server |     response = response or self.get_response(request)
CollectionUsers_server |   File "/root/.local/share/virtualenvs/server-MrgTHRtU/lib/python3.8/site-packages/django/core/handlers/exception.py", line 47, in inner
CollectionUsers_server |     response = get_response(request)
CollectionUsers_server |   File "/root/.local/share/virtualenvs/server-MrgTHRtU/lib/python3.8/site-packages/django/utils/deprecation.py", line 117, in __call__
CollectionUsers_server |     response = response or self.get_response(request)
CollectionUsers_server |   File "/root/.local/share/virtualenvs/server-MrgTHRtU/lib/python3.8/site-packages/django/core/handlers/exception.py", line 47, in inner
CollectionUsers_server |     response = get_response(request)
CollectionUsers_server |   File "/root/.local/share/virtualenvs/server-MrgTHRtU/lib/python3.8/site-packages/django/utils/deprecation.py", line 117, in __call__
CollectionUsers_server |     response = response or self.get_response(request)
CollectionUsers_server |   File "/root/.local/share/virtualenvs/server-MrgTHRtU/lib/python3.8/site-packages/django/core/handlers/exception.py", line 47, in inner
CollectionUsers_server |     response = get_response(request)
CollectionUsers_server |   File "/root/.local/share/virtualenvs/server-MrgTHRtU/lib/python3.8/site-packages/django/utils/deprecation.py", line 117, in __call__
CollectionUsers_server |     response = response or self.get_response(request)
CollectionUsers_server |   File "/root/.local/share/virtualenvs/server-MrgTHRtU/lib/python3.8/site-packages/django/core/handlers/exception.py", line 47, in inner
CollectionUsers_server |     response = get_response(request)
CollectionUsers_server |   File "/root/.local/share/virtualenvs/server-MrgTHRtU/lib/python3.8/site-packages/django/core/handlers/base.py", line 181, in _get_response
CollectionUsers_server |     response = wrapped_callback(request, *callback_args, **callback_kwargs)
CollectionUsers_server |   File "/root/.local/share/virtualenvs/server-MrgTHRtU/lib/python3.8/site-packages/django/views/generic/base.py", line 70, in view
CollectionUsers_server |     return self.dispatch(request, *args, **kwargs)
CollectionUsers_server |   File "/root/.local/share/virtualenvs/server-MrgTHRtU/lib/python3.8/site-packages/django/utils/decorators.py", line 43, in _wrapper
CollectionUsers_server |     return bound_method(*args, **kwargs)
CollectionUsers_server |   File "/root/.local/share/virtualenvs/server-MrgTHRtU/lib/python3.8/site-packages/django/views/decorators/csrf.py", line 54, in wrapped_view
CollectionUsers_server |     return view_func(*args, **kwargs)
CollectionUsers_server |   File "/root/.local/share/virtualenvs/server-MrgTHRtU/lib/python3.8/site-packages/strawberry/django/views.py", line 148, in dispatch
CollectionUsers_server |     result = self.schema.execute_sync(

"Cannot query field 'tokenAuth' on type 'Mutation'."

EDIT: I made this work by swithching from sync to async:

  • AsyncGraphQLView -> GraphQLView in /urls.py
  • AsyncJSONWebTokenMiddleware -> JSONWebTokenMiddleware
  • Remove sync_to_async from resolvers
    Though, the problem that raised with it is that my GraphQL explorer cannot longer obtain my schema, disabling autocomplete function. I describe this problem further in 245

I followed the readme to make the simplest of implementations. Not only I can't see my schema on my GraphiGL explorer. When I run the authToken query:

mutation($email: String!, $password: String!){
 authToken(email:$email, password: $password){
  token
}
}

and got the following back:

{
  "data": null,
  "errors": [
    {
      "message": "Cannot query field 'tokenAuth' on type 'Mutation'.",
      "locations": [
        {
          "line": 2,
          "column": 2
        }
      ],
      "path": null
    }
  ]
}

Here are my settings:

import os
from pathlib import Path


BASE_DIR = Path(__file__).resolve().parent.parent

SECRET_KEY = os.environ.get("SECRET_KEY")

DEBUG = os.environ.get("DEBUG")

ALLOWED_HOSTS = [el for el in os.environ.get("ALLOWED_HOSTS").split(",")]

INSTALLED_APPS = [
    "django.contrib.admin",
    "django.contrib.auth",
    "django.contrib.contenttypes",
    "django.contrib.sessions",
    "django.contrib.messages",
    "django.contrib.staticfiles",
    # Project apps
    "users",
    # Third party apps
    "corsheaders",
    'strawberry_django_jwt.refresh_token',
]

MIDDLEWARE = [
    "django.middleware.security.SecurityMiddleware",
    "django.contrib.sessions.middleware.SessionMiddleware",
    "corsheaders.middleware.CorsMiddleware",
    "django.middleware.common.CommonMiddleware",
    "django.middleware.csrf.CsrfViewMiddleware",
    "django.contrib.auth.middleware.AuthenticationMiddleware",
    "django.contrib.messages.middleware.MessageMiddleware",
    "django.middleware.clickjacking.XFrameOptionsMiddleware",
]

AUTHENTICATION_BACKENDS = [
    'strawberry_django_jwt.backends.JSONWebTokenBackend',
    'django.contrib.auth.backends.ModelBackend',
]

ROOT_URLCONF = "project.urls"

TEMPLATES = [
    {
        "BACKEND": "django.template.backends.django.DjangoTemplates",
        "DIRS": [],
        "APP_DIRS": True,
        "OPTIONS": {
            "context_processors": [
                "django.template.context_processors.debug",
                "django.template.context_processors.request",
                "django.contrib.auth.context_processors.auth",
                "django.contrib.messages.context_processors.messages",
            ],
        },
    },
]

WSGI_APPLICATION = "project.wsgi.application"

DATABASES = {
    "default": {
        "ENGINE": os.environ.get("SQL_ENGINE"),
        "NAME": os.environ.get("SQL_DATABASE"),
        "USER": os.environ.get("SQL_USER"),
        "PASSWORD": os.environ.get("SQL_PASSWORD"),
        "HOST": os.environ.get("SQL_HOST"),
        "PORT": os.environ.get("SQL_PORT"),
    }
}

AUTH_PASSWORD_VALIDATORS = [
    {
        "NAME": "django.contrib.auth.password_validation.UserAttributeSimilarityValidator",
    },
    {
        "NAME": "django.contrib.auth.password_validation.MinimumLengthValidator",
    },
    {
        "NAME": "django.contrib.auth.password_validation.CommonPasswordValidator",
    },
    {
        "NAME": "django.contrib.auth.password_validation.NumericPasswordValidator",
    },
]

LANGUAGE_CODE = "en-us"

TIME_ZONE = "UTC"

USE_I18N = True

USE_L10N = True

USE_TZ = True

STATIC_URL = "/static/"

AUTH_USER_MODEL = "users.CustomUser"

DEFAULT_AUTO_FIELD = "django.db.models.BigAutoField"

AUTHENTICATION_BACKENDS = [
    'strawberry_django_jwt.backends.JSONWebTokenBackend',
    'django.contrib.auth.backends.ModelBackend',
]


GRAPHQL_JWT = {"JWT_AUTHENTICATE_INTROSPECTION": True}

My schema:

import strawberry
import strawberry_django_jwt.mutations as jwt_mutations
from strawberry_django_plus import directives, gql, optimizer
from strawberry_django_jwt.middleware import AsyncJSONWebTokenMiddleware
import strawberry_django_jwt.mutations as jwt_mutations
from asgiref.sync import sync_to_async as _


@gql.type
class Mutation:
    # JWT
    token_auth          = _(jwt_mutations.ObtainJSONWebToken.obtain)
    verify_token        = _(jwt_mutations.Verify.verify)
    refresh_token       = _(jwt_mutations.Refresh.refresh)
    delete_token_cookie = _(jwt_mutations.DeleteJSONWebTokenCookie.delete_cookie)

schema = strawberry.Schema(
    query=Query,
    mutation=Mutation,
    extensions=[
        optimizer.DjangoOptimizerExtension,
        directives.SchemaDirectiveExtension,
        AsyncJSONWebTokenMiddleware
    ],
)

Installed packages:

[tool.poetry]
name = "workspace"
version = "0.1.0"
description = ""
authors = ["Lucas <[email protected]>"]

[tool.poetry.dependencies]
python = "^3.10"
django = "3.2"
starlette = "0.16"
six = "^1.16.0"
strawberry-graphql = {extras = ["debug-server"], version = "^0.95.0"}
psycopg2-binary = "^2.9.3"
django-cors-headers = "^3.11.0"
gunicorn = "^20.1.0"
httptools = "^0.3.0"
uvloop = "^0.16.0"
strawberry-django-plus = "^1.1.2"
typing_extensions = "^4.1.1"
isort = "^5.10.1"
black = "^22.1.0"
pytest = "^7.0.1"
pytest-rerunfailures = "^10.2"
pytest-django = "^4.5.2"
pytest-cov = "^3.0.0"
flake8 = "^4.0.1"
mypy = "^0.931"
strawberry-django-jwt = "^0.2.0"
django-graphql-jwt = "^0.3.4"

[tool.poetry.dev-dependencies]
django-simple-history = "^3.0.0"
django-extensions = "^3.1.5"

[build-system]
requires = ["poetry>=0.12"]
build-backend = "poetry.masonry.api"

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.