kundapanda / strawberry-django-jwt Goto Github PK
View Code? Open in Web Editor NEWThis project forked from flavors/django-graphql-jwt
[UNMAINTAINED] JSON Web Token (JWT) authentication for Django with Strawberry GraphQL
License: MIT License
This project forked from flavors/django-graphql-jwt
[UNMAINTAINED] JSON Web Token (JWT) authentication for Django with Strawberry GraphQL
License: MIT License
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.
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.
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 :
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
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.
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
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.
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.
.timestamp()
returns POSIX timestamp as a float, so this causes an error because refresh_expires_in expects an int
.
strawberry-django-jwt/strawberry_django_jwt/utils.py
Lines 255 to 257 in 54ad4b0
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.
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.
I would expect that if user login he gets new refresh token and the previous will be deleted automatically,
am i right?
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.
The new strawberry 0.121.0 update changes how default field resolvers work. The get_result
function has been completely removed, and its' content moved to the from_resolver
function (strawberry-graphql/strawberry@0.120.0...0.121.0#diff-00af9d43c9b59404ba170e72e470939f2a6dd50e2eae24d0e24ef105431e5414L284).
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?
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
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,
],
)
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.
My project does not currently use Django Rest Framework, so on line 15 of utils.py, i get an ImportError
from strawberry-django-jwt
.
Is Django Rest Framework necessary? It feels strange to need DRF when using GraphQL.
Hi,
It seems that there's another dependency issue, I can't install the recent release of strawberry-graphql (>=0.90.0) as strawberry-django-jwt requires <0.90.0,>=0.69.0.
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:
It seems like the explorer is suddenly not obtaining something it's looking for:
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
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...
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?
Fixed in #138
Broken due to internal changes to StrawberryField, currently trying to resolve this
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.
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
Broken due to internal changes in the strawberry-graphql library.
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?
Is this library compatible with Strawberry Django integration? I have not found any way to use the login_required
decorator with the strawberry_django.field
from https://github.com/strawberry-graphql/strawberry-graphql-django.
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.
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
In 0.74.0 version of strawberry-graphql, custom schema middlewares were removed. As this project uses custom middleware to process headers/cookies, some workaround has to be created.
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-django-jwt/strawberry_django_jwt/object_types.py
Lines 45 to 50 in 54ad4b0
I think this could be resolved by changing the call to result = TokenDataType(payload=payload, token=token, refresh_expired_in=refresh_expires_in)
.
https://nrbnlulu.github.io/strawberry-django-auth
I will try to post the errors that I face If I face anything :D
Is there a way (through middleware or something) to attach access-tokens to requests where login is required?
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(
EDIT: I made this work by swithching from sync to async:
AsyncGraphQLView
-> GraphQLView
in /urls.py
AsyncJSONWebTokenMiddleware
-> JSONWebTokenMiddleware
sync_to_async
from resolversI 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"
A declarative, efficient, and flexible JavaScript library for building user interfaces.
๐ Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. ๐๐๐
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google โค๏ธ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.