Giter Club home page Giter Club logo

django-graphql-auth's Introduction

Django GraphQL Auth

Django registration and authentication with GraphQL.

downloads Codecov Coverage Build Status Pypi Documentation Status contributions welcome

Demo

Demo Video

About

Abstract all the basic logic of handling user accounts out of your app, so you don't need to think about it and can get up and running faster.

No lock-in. When you are ready to implement your own code or this package is not up to your expectations , it's easy to extend or switch to your implementation.

Documentation

Documentation is available at read the docs.

Features

  • Awesome docs ๐ŸŽ‰
  • Fully compatible with Relay
  • Works with default or custom user model
  • JWT authentication (with Django GraphQL JWT)
  • User query with filters (with Django Filter and Graphene Django)
  • User registration with email verification
  • Add secondary email, with email verification too
  • Resend activation email
  • Retrieve/Update user
  • Archive user
  • Permanently delete user or make it inactive
  • Turn archived user active again on login
  • Track user status (archived, verified, secondary email)
  • Password change
  • Password reset through email
  • Revoke user refresh tokens on account archive/delete/password change/reset
  • All mutations return success and errors
  • Default email templates (you will customize though)
  • Customizable, no lock-in

Full Schema

import graphene

from graphql_auth.schema import UserQuery, MeQuery
from graphql_auth import mutations

class AuthMutation(graphene.ObjectType):
    register = mutations.Register.Field()
    verify_account = mutations.VerifyAccount.Field()
    resend_activation_email = mutations.ResendActivationEmail.Field()
    send_password_reset_email = mutations.SendPasswordResetEmail.Field()
    password_reset = mutations.PasswordReset.Field()
    password_set = mutations.PasswordSet.Field() # For passwordless registration
    password_change = mutations.PasswordChange.Field()
    update_account = mutations.UpdateAccount.Field()
    archive_account = mutations.ArchiveAccount.Field()
    delete_account = mutations.DeleteAccount.Field()
    send_secondary_email_activation =  mutations.SendSecondaryEmailActivation.Field()
    verify_secondary_email = mutations.VerifySecondaryEmail.Field()
    swap_emails = mutations.SwapEmails.Field()
    remove_secondary_email = mutations.RemoveSecondaryEmail.Field()

    # django-graphql-jwt inheritances
    token_auth = mutations.ObtainJSONWebToken.Field()
    verify_token = mutations.VerifyToken.Field()
    refresh_token = mutations.RefreshToken.Field()
    revoke_token = mutations.RevokeToken.Field()


class Query(UserQuery, MeQuery, graphene.ObjectType):
    pass


class Mutation(AuthMutation, graphene.ObjectType):
    pass


schema = graphene.Schema(query=Query, mutation=Mutation)

Relay

Import mutations from the relay module:

from graphql_auth import relay

class AuthMutation(graphene.ObjectType):
   register = relay.Register.Field()
   # ...

Example

Handling user accounts becomes super easy.

mutation {
  register(
    email: "[email protected]",
    username: "new_user",
    password1: "123456super",
    password2: "123456super",
  ) {
    success,
    errors,
    token,
    refreshToken
  }
}

Check the status of the new user:

u = UserModel.objects.last()
u.status.verified
# False

During the registration, an email with a verification link was sent.

mutation {
  verifyAccount(
    token:"<TOKEN ON EMAIL LINK>",
  ) {
    success,
    errors
  }
}

Now user is verified.

u.status.verified
# True

Check the installation guide or jump to the quickstart. Or if you prefer, browse the api.

Contributing

See CONTRIBUTING.md

django-graphql-auth's People

Contributors

aalhendi avatar boolangery avatar burnysc2 avatar bzhr avatar capaci avatar dependabot[bot] avatar hashlash avatar imsheldon avatar joshuachinemezu avatar maxpeterson avatar mnieber avatar panosangelopoulos avatar pedrobern avatar pors avatar ulgens avatar yanivtoledano 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  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  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  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

django-graphql-auth's Issues

Support django-graphql-jwt==0.3.1? Maybe resolve issue with info.context.user (permission)

I try to get id with other model than user (or extend user model)
I use

@login_required
    def resolve_posts_partner(self, info):
        print(info.context.user.id, 'my user partner id')
        return Post.objects.order_by('-updated_at').filter(partner_id=info.context.user.id)

and I have
image

When i delete @login_required

I have
image

problem with info.context.user.id

Maybe who help me?

Package does not support custom user model.

I have been using this package for a little while now and I have some issues.

My customer user models have the following fields defined.

  1. Full name.

  2. Email

But when I installed this package I was given this error which states.

Unknown field(s) (last_name, first_name) specified for User

I do not have a last name and first name field specified in my custom user model, How do I override this ???

[Error!]: Invalid Token in verifyAccount Mutation

Prerequisites

  • Is it a bug?
  • Is it a new feature?
  • Is it a a question?
  • Can you reproduce the problem?
  • Are you running the latest version?
  • Did you check for similar issues?
  • Did you perform a cursory search?

For more information, see the CONTRIBUTING guide.

Description

VerifyAccount Mutation doesn't works

I've followed the installation instructions and checked the Quickstart project to see if I've done anything wrong. The verifyAccount mutation fails. It throws me the error of: Invalid token

Issue Video

Oooh... the gif is too small... Here the process:

  1. Register

register

  1. VerifyToken

verifyToken

  1. VerifyAccount

verifyAccount

Return id in APIs such as verifyEmail

Prerequisites

  • Is it a bug?
  • [x ] Is it a new feature?
  • Is it a a question?
  • Can you reproduce the problem?
  • Are you running the latest version?
  • Did you check for similar issues?
  • Did you perform a cursory search?

For more information, see the CONTRIBUTING guide.

Description

In some GraphQL clients like Apollo they can atomically refresh a query when a mutation is applied this can be useful when wanting to have the UI show the latest state.

When verifying a user its useful for the UI to automatically update with the latest verification state however at the moment the mutation APIs don't return the ID of the user who was verified so these libraries won't automatically handle it and instead you have to explicitly ask them to do it.

By adding the id field to the response we can allow Apollo users to have this behaviour out of the box.

New installation does not migrate existing users

Description

When installing into a project, the package functionality does not work with any of the users that already existed before the package was added. Presumably because the existing users aren't added into the graphql_auth_userstatus table.

Not sure if this is a bug or new request

Steps to Reproduce

If we need to reproduce and you don't provide steps for it, it will be closed. Alternatively, you can link a repo with the code to run your issue.

  1. Have existing users registered without django-graphql-auth
  2. Install django-graphql-auth and run migration
  3. Attempt to use any of the functions (i.e., verifyToken)

Expected behavior

Attempting to use any of the functions with an existing user should work without any extra steps (or at least minimal extra steps via some sort of management command). Works fine with users created after the fact.

Actual behavior

Nothing happens when attempting to use any of the package features for existing users. (i.e., verifyToken returns null for token, sendPasswordResetEmail does nothing).

Requirements

aioredis==1.3.1
aniso8601==7.0.0
asgiref==3.2.10
asn1crypto==1.4.0
astroid==2.4.2
async-timeout==3.0.1
attrs==20.2.0
autobahn==20.7.1
Automat==20.2.0
bcrypt==3.2.0
blessed==1.17.10
boto3==1.14.61
botocore==1.17.61
cached-property==1.5.1
cement==3.0.4
certifi==2020.6.20
cffi==1.14.2
channels==2.4.0
channels-redis==3.1.0
chardet==3.0.4
colorama==0.4.3
constantly==15.1.0
cryptography==3.1
daphne==2.5.0
distro==1.5.0
Django==3.1.1
django-cleanup==5.1.0
django-cors-headers==3.5.0
django-filter==2.4.0
django-graphql-auth==0.3.12
django-graphql-jwt==0.3.0
django-guardian==2.3.0
django-polymorphic==3.0.0
django-storages==1.10
djangorestframework==3.11.1
docker==4.3.1
docker-compose==1.27.2
docker-pycreds==0.4.0
dockerpty==0.4.1
docopt==0.6.2
docutils==0.16
graphene==2.1.8
graphene-django==2.13.0
graphene-file-upload==1.2.2
graphql-core==2.3.1
graphql-relay==2.0.1
graphql-ws==0.3.0
hiredis==1.1.0
hyperlink==20.0.1
idna==2.10
importlib-metadata==1.7.0
incremental==17.5.0
isort==5.5.2
jmespath==0.9.4
jsonschema==3.1.1
lazy-object-proxy==1.4.2
mccabe==0.6.1
more-itertools==7.2.0
msgpack==0.6.2
paramiko==2.6.0
pathspec==0.6.0
pbr==5.4.3
Pillow==7.2.0
promise==2.3
psycopg2==2.8.6
pyasn1==0.4.8
pyasn1-modules==0.2.8
pycparser==2.20
PyHamcrest==1.9.0
PyJWT==1.7.1
pylint==2.4.4
PyNaCl==1.3.0
pyOpenSSL==19.1.0
pyrsistent==0.15.4
python-dateutil==2.7.5
python-dotenv==0.14.0
pytz==2018.5
PyYAML==4.2b1
requests==2.20.0
Rx==1.6.1
s3transfer==0.3.3
semantic-version==2.5.0
sentry-sdk==0.17.5
service-identity==18.1.0
singledispatch==3.4.0.3
six==1.14.0
sqlparse==0.3.1
stevedore==1.30.1
stripe==2.43.0
termcolor==1.1.0
texttable==0.9.1
Twisted==20.3.0
txaio==18.8.1
typed-ast==1.4.0
Unidecode==1.1.1
urllib3==1.24.3
wcwidth==0.1.7
websocket-client==0.57.0
wrapt==1.12.1
zipp==3.1.0
zope.interface==5.0.0

Support For Logout?

@PedroBern First of all, huge thanks for this repo and the great documentation. Very helpful indeed. I see that a lot of authentication methods have been implemented by a key one is missing. Once a user has been authenticated and logged in, how can that user then logout again?

I might be missing something fundamental however so any insight is appreciated!

Can't exclude user node fields "id" and "pk"

I have this setting:

"USER_NODE_EXCLUDE_FIELDS": ["password", "is_superuser", "id", "pk"]

And I get this warning:

.../graphene_django/types.py:103: UserWarning: Excluding the custom field "id" on DjangoObjectType "UserNode" has no effect. Either remove the custom field or remove the field from the "exclude" list.

And the same for pk.

[Errno 111] Connection refused

Prerequisites

  • Is it a bug?
  • Is it a new feature?
  • Is it a a question?
  • Can you reproduce the problem?
  • Are you running the latest version?
  • Did you check for similar issues?
  • Did you perform a cursory search?

Description

I am trying to build an API for a transportation system which has different kind of users (Driver, Customer, SystemAdmin and Authorizer). For this purpose I created an AbstractUser and use inheritance relationship for the all of the above different users.
For adding JWT to the model, I have read the official tutorial, but whenever I want to create a new user like the following I faced to the error:

mutation {
  register(
    email: "[email protected]",
    username: "new_user",
    password1: "supersecretpassword",
    password2: "supersecretpassword",
  ) {
    success,
    errors,
    token,
    refreshToken
  }
}

Steps to Reproduce

  1. Here is my model:
from django.db import models
from django.contrib.auth.models import AbstractUser


# Create your models here.
class Usermodel(AbstractUser, models.Model):
    phone_no = models.CharField(
        max_length=11,
        blank=True,
        verbose_name="Phone Number"
    )

    USERNAME_FIELD = "username"   # e.g: "username", "email"
    EMAIL_FIELD = "email"         # e.g: "email", "primary_email"
    
    def __str__(self):
        return self.username

    
class Driver(Usermodel, models.Model):
    national_id = models.CharField(
        max_length=10, 
        blank=True, 
        verbose_name="National ID"
    )

    profile_picture = models.ImageField(
        blank=True,
        null=True
    )

    STATUS_CHOICES = [
        ('1', 'Free'),
        ('2', 'Busy')
    ]

    driver_status = models.CharField(
        max_length=1,
        choices=STATUS_CHOICES
    )

    rating = models.FloatField(
        default=-1
    )

    ranking = models.IntegerField(
        default=-1
    )

    class Meta:
        verbose_name = 'Driver'
        verbose_name_plural = 'Drivers'

class Authorizer(Usermodel, models.Model):
    class Meta:
        verbose_name = 'Authorizer'
        verbose_name_plural = 'Authorizers'

class Customer(Usermodel, models.Model):
    class Meta:
        verbose_name = 'Customer'
        verbose_name_plural = 'Customers'

class Administrator(Usermodel, models.Model):
    class Meta:
        verbose_name='Adminsitrator'
        verbose_name_plural='Administrators'
  1. users schema
import graphene
from graphene import Mutation, ObjectType, InputObjectType
from .models import Driver, Authorizer, Customer, Administrator
from graphene_django.types import DjangoObjectType


class DriverType(DjangoObjectType):
    class Meta:
        model = Driver

class AuthorizerType(DjangoObjectType):
    class Meta:
        model = Authorizer

class Query(ObjectType):
    driver = graphene.Field(
        DriverType,
        id = graphene.ID()
    )

    authorizer = graphene.Field(
        AuthorizerType,
        id = graphene.ID()
    )

    all_drivers = graphene.List(DriverType)
    all_authorizers = graphene.List(AuthorizerType)

    def resolve_all_drivers(self, info, **kwargs):
        return Driver.objects.all()

    def resolve_driver(self, info, **kwargs):
        id = kwargs.get('id')
        if id is not None:
            return Driver.objects.get(pk=id)

    def resolve_authorizer(self, info, **kwargs):
        id = kwargs.get('id')
        if id is not None:
            return Driver.objects.get(pk=id)

    def resolve_all_authorizers(self, info, **kwargs):
        return Authorizer.objects.all()


class DriverInput(InputObjectType):
    first_name = graphene.String()
    last_name = graphene.String()
    email = graphene.String()
    username = graphene.String()
    phone_no = graphene.String()
    national_id = graphene.String()
    password = graphene.String()


class AuthorizerInput(InputObjectType):
    first_name = graphene.String()
    last_name = graphene.String()
    email = graphene.String()
    username = graphene.String()
    phone_no = graphene.String()
    password = graphene.String()
class CreateDriver(Mutation):
    class Arguments:
        driver_data = DriverInput()
        
    driver = graphene.Field(DriverType)

    def mutate(self, info, driver_data=None):
        driver = Driver(
            first_name=driver_data.first_name,
            last_name=driver_data.last_name,
            email=driver_data.email,
            username=driver_data.username,
            phone_no=driver_data.phone_no,
            national_id=driver_data.national_id,
            password=driver_data.password
        )

        driver.save()

        return CreateDriver(
            driver=driver
        )

class UpdateDriver(Mutation):
    class Arguments:
        id = graphene.ID()
        driver_data = DriverInput()
    
    driver = graphene.Field(DriverType)

    def mutate(self, info, id, driver_data=None):
        #TODO: Error handling if the id not exists
        driver = Driver.objects.get(pk=id)

        driver.first_name = driver_data.first_name
        driver.last_name = driver_data.last_name
        driver.email = driver_data.email
        driver.username = driver_data.username
        driver.phone_no = driver_data.phone_no
        driver.national_id = driver_data.national_id
        driver.password = driver_data.password
        driver.save()

        return UpdateDriver(driver=driver)


class AuthorizerInput(InputObjectType):
    first_name = graphene.String()
    last_name = graphene.String()
    email = graphene.String()
    username = graphene.String()
    phone_no = graphene.String()
    password = graphene.String()

class CreateAuthorizer(Mutation):
    class Arguments:
        authorizer_data = AuthorizerInput()

    authorizer = graphene.Field(AuthorizerInput)

    def mutate(self, info, authorizer_data=None):
        authorizer = Authorizer(
            firstname=authorizer_data.first_name,
            last_name=authorizer_data.last_name,
            email=authorizer_data.email,
            username=authorizer_data.username,
            phone_no=authorizer_data.phone_no,
            password=authorizer_data.password
        )
        authorizer.save()
        return CreateAuthorizer(authorizer=authorizer)

class UpdateAuthorizer(Mutation):
    class Arguments:
        id = graphene.ID()
        authorizer_data = AuthorizerInput()
    
    authorizer = graphene.Field(AuthorizerType)
    
    def mutate(self, info, id, authorizer_data=None):
        authorizer = Authorizer.objects.get(pk=id)
        authorizer.first_name = authorizer_data.first_name
        authorizer.last_name = authorizer_data.last_name
        authorizer.email = authorizer_data.email
        authorizer.username = authorizer_data.username
        authorizer.password = authorizer_data.password
        authorizer.save()

        return UpdateDriver(authorizer=authorizer)

class Mutations(ObjectType):
    create_driver = CreateDriver.Field()
    update_driver = UpdateDriver.Field()
  1. project schema
import graphene

from apps.users.schema import Query as user_query
from apps.users.schema import Mutations as user_mutation
from graphql_auth.schema import UserQuery, MeQuery
from graphql_auth import mutations

class AuthMutation(graphene.ObjectType):
   register = mutations.Register.Field()


class Query(user_query, UserQuery, MeQuery):
    pass

class Mutations(user_mutation, AuthMutation):
    pass    

schema = graphene.Schema(
    query=Query,
    mutation=Mutations
)

Expected behavior

I expect the code to run without any problem but face to the following error in actual behavior

I also have another question. As I have explained for the various kind of user and registration of them, I need different arguments. But in schema we just add register = mutations.Register.Field(), How can I reach to this purpose?

Actual behavior

error description

Requirements

aniso8601==7.0.0
asgiref==3.2.10
Django==3.0.8
django-filter==2.3.0
django-graphql-auth==0.3.11
django-graphql-jwt==0.3.0
graphene==2.1.8
graphene-django==2.12.1
graphql-core==2.3.2
graphql-relay==2.0.1
Pillow==7.2.0
pkg-resources==0.0.0
promise==2.3
PyJWT==1.7.1
pytz==2020.1
Rx==1.6.1
singledispatch==3.4.0.3
six==1.15.0
sqlparse==0.3.1
Unidecode==1.1.1

Graphql login does not return token

When I try to log in and it does not return a JSON Token

mutation {
tokenAuth(email: "[email protected]", password: "oldskool123") {
success,
errors,
unarchiving,
token,
refreshToken,
unarchiving,

}
}

{
"data": {
"tokenAuth": {
"success": false,
"errors": {
"nonFieldErrors": [
{
"message": "Please, enter valid credentials.",
"code": "invalid_credentials"
}
]
},
"unarchiving": false,
"token": null
}
}
}

ALLOW_LOGIN_NOT_VERIFIED does not support graphql_auth.mutations.SendPasswordResetEmail

Description

Setting ALLOW_LOGIN_NOT_VERFIED to True seems like it would eliminate the UserNotVerifiedError upon executing the SendPasswordResetEmail (in the case where user is unverified), however, it still raises this error.

Expected behavior

I would expect ALLOW_LOGIN_NOT_VERFIED would remove the check for the user needing to be verified upon sending the password reset email - or I would expect there to be a new setting called ALLOW_PASSWORD_RESET_NOT_VERIFIED that would more granularly control this.

Requirements

django-graphql-jwt==0.3.0
graphene-django==2.9.1
django-graphql-auth==0.3.10

Detach authorization-related errors from form-field errors

Description

When receiving a response back from a graphql query or mutation implemented in django-graphql-auth that includes an error, the response is nested within the "data" map instead of as a top-level key per the graphql spec: https://github.com/graphql/graphql-spec/blob/master/spec/Section%207%20--%20Response.md

e.g. actual response for an invalid email address to the "Register" mutation:
{"data":{"register":{"success":false,"errors":{"email":[{"message":"Enter a valid email address.","code":"invalid"}]},__typename":"Register"}}}

Expected response:
{errors:[{"message":"Enter a valid email address.","code":"invalid", "path":["register","user","email"]}],"data":{}}

Steps to Reproduce

  • Send a GraphQL mutation payload to Django that uses any of the mutations defined in this library that would return an error.

This appears to be the problem:

I haven't tested it out, but this may "just work" without this error handling, instead letting graphene handle raised exceptions.

Not following the GraphQL spec and custom formatting errors like this make it difficult to use this library in conjunction with a frontend graphql client that has built in error handling (e.g. Apollo or Relay). Instead of using their error workflows, you have to write your own to parse out the "data" payload looking for errors since they expect all errors to appear as a top-level key "errors".

For what its worth, django-graphql-jwt does implement error handling to spec.

Generate JWT by user

Prerequisites

  • Is it a bug?
  • Is it a new feature?
  • [x ] Is it a a question?
  • Can you reproduce the problem?
  • Are you running the latest version?
  • Did you check for similar issues?
  • Did you perform a cursory search?

For more information, see the CONTRIBUTING guide.

Description

Am I able to generate a JWT by adding a user to a function with this package? My goal is to be able to generate a JWT from a SSO sign in :D

Unknown field(s) (username) specified for User

I get this error when I implement this into my existing custom user model that does not have a username field attached to it.
my custom user model only supports email, full name and password.

Environment:

Request Method: GET
Request URL: http://127.0.0.1:8000/

Django Version: 2.2.9
Python Version: 3.8.3
Installed Applications:
['django.contrib.admin',
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
'django.contrib.sites',
'accounts',
'post',
'comment',
'userprofile',
'job',
'schedule',
'hashtag',
'billing',
'corsheaders',
'graphene_django',
'django_fsm_log',
'subscriptions.apps.SubscriptionsConfig',
'graphql_auth']
Installed 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']

Traceback:

File "C:\Users\Udemezue\Desktop\resume-backend\env\lib\site-packages\django\core\handlers\exception.py" in inner
34. response = get_response(request)

File "C:\Users\Udemezue\Desktop\resume-backend\env\lib\site-packages\django\core\handlers\base.py" in _get_response
115. response = self.process_exception_by_middleware(e, request)

File "C:\Users\Udemezue\Desktop\resume-backend\env\lib\site-packages\django\core\handlers\base.py" in _get_response
113. response = wrapped_callback(request, *callback_args, **callback_kwargs)

File "C:\Users\Udemezue\Desktop\resume-backend\env\lib\site-packages\django\views\decorators\csrf.py" in wrapped_view
54. return view_func(*args, **kwargs)

File "C:\Users\Udemezue\Desktop\resume-backend\env\lib\site-packages\django\views\generic\base.py" in view
62. self = cls(**initkwargs)

File "C:\Users\Udemezue\Desktop\resume-backend\env\lib\site-packages\graphene_django\views.py" in init
79. schema = graphene_settings.SCHEMA

File "C:\Users\Udemezue\Desktop\resume-backend\env\lib\site-packages\graphene_django\settings.py" in getattr
117. val = perform_import(val, attr)

File "C:\Users\Udemezue\Desktop\resume-backend\env\lib\site-packages\graphene_django\settings.py" in perform_import
56. return import_from_string(val, setting_name)

File "C:\Users\Udemezue\Desktop\resume-backend\env\lib\site-packages\graphene_django\settings.py" in import_from_string
70. module = importlib.import_module(module_path)

File "C:\Users\Udemezue\AppData\Local\Programs\Python\Python38-32\lib\importlib_init_.py" in import_module
127. return _bootstrap._gcd_import(name[level:], package, level)

File "" in _gcd_import
1014.

File "" in _find_and_load
991.

File "" in _find_and_load_unlocked
975.

File "" in _load_unlocked
671.

File "" in exec_module
783.

File "" in _call_with_frames_removed
219.

File "C:\Users\Udemezue\Desktop\resume-backend\src\resume\resume\graph\schema.py" in
45. from graphql_auth import mutations

File "C:\Users\Udemezue\Desktop\resume-backend\env\lib\site-packages\graphql_auth\mutations.py" in
5. from .mixins import (

File "C:\Users\Udemezue\Desktop\resume-backend\env\lib\site-packages\graphql_auth\mixins.py" in
15. from .forms import RegisterForm, EmailForm, UpdateAccountForm

File "C:\Users\Udemezue\Desktop\resume-backend\env\lib\site-packages\graphql_auth\forms.py" in
9. class RegisterForm(UserCreationForm):

File "C:\Users\Udemezue\Desktop\resume-backend\env\lib\site-packages\django\forms\models.py" in new
266. raise FieldError(message)

Exception Type: FieldError at /
Exception Value: Unknown field(s) (username) specified for User

Register staff by admin account

Currently, we can use the REGISTER_MUTATION_FIELDS to specify which fields we want to be at the registration, but @bzhr pointed out that it can lead to some problems when we need to make sure for example to allow only admin users to create staff users.

An easy fix for this, in my opinion, would be building a new mutation, something like InternalRegister that works very similar to the Register, but for the admin users use in mind.

Some specification:

  • Only admin or staff users have access
  • New setting to define who has access to it (superuser or staff)
  • New setting to specify behavior, for example, maybe the email verification isn't necessary for staff users.
  • What else?

@bzhr can you work on this?

Create user without password by using set_unusable_password

Prerequisites

  • Is it a bug?
  • Is it a new feature?
  • Is it a a question?
  • Can you reproduce the problem?
  • Are you running the latest version?
  • Did you check for similar issues?
  • Did you perform a cursory search?

Description

I want to be able to call the register mutation without having to pass the password1 and password2 args, thus using set_unusable_password() for creating a new account. Any recommendations on how to go about this?

Custom template variables in settings

Current behaviour
Currently, in email templates, Django host URLs are getting populated.

Better approach
If as a developer, I want to handle the email activation through front-end. Then I need to set the pass the front-end URL in templates.

The solution we can go with:
We can set the frontend URL in settings and use that in required places in the package.

User has no status error.

I follow the Quickstart guide and the query

query {
  users {
    edges {
      node {
        id,
        username,
        archived,
        verified,
        email,
        secondaryEmail,
      }
    }
  }
}

triggers the following error:

ERROR 2020-02-24 18:10:10,231 utils 26762 123145366966272 Traceback (most recent call last):
  File "/Users/mark/.pyenv/versions/ve381/lib/python3.8/site-packages/promise/promise.py", line 489, in _resolve_from_executor
    executor(resolve, reject)
  File "/Users/mark/.pyenv/versions/ve381/lib/python3.8/site-packages/promise/promise.py", line 756, in executor
    return resolve(f(*args, **kwargs))
  File "/Users/mark/.pyenv/versions/ve381/lib/python3.8/site-packages/graphql/execution/middleware.py", line 75, in make_it_promise
    return next(*args, **kwargs)
  File "/Users/mark/.pyenv/versions/ve381/lib/python3.8/site-packages/graphql_auth/schema.py", line 26, in resolve_archived
    return self.status.archived
  File "/Users/mark/.pyenv/versions/ve381/lib/python3.8/site-packages/django/db/models/fields/related_descriptors.py", line 420, in __get__
    raise self.RelatedObjectDoesNotExist(
graphql.error.located_error.GraphQLLocatedError: User has no status.

The graphql result is:

{
  "errors": [
    {
      "message": "User has no status.",
      "locations": [
        {
          "line": 37,
          "column": 9
        }
      ],
      "path": [
        "users",
        "edges",
        0,
        "node",
        "archived"
      ]
    },
    {
      "message": "User has no status.",
      "locations": [
        {
          "line": 38,
          "column": 9
        }
      ],
      "path": [
        "users",
        "edges",
        0,
        "node",
        "verified"
      ]
    },
    {
      "message": "User has no status.",
      "locations": [
        {
          "line": 40,
          "column": 9
        }
      ],
      "path": [
        "users",
        "edges",
        0,
        "node",
        "secondaryEmail"
      ]
    },
    {
      "message": "User has no status.",
      "locations": [
        {
          "line": 37,
          "column": 9
        }
      ],
      "path": [
        "users",
        "edges",
        1,
        "node",
        "archived"
      ]
    },
    {
      "message": "User has no status.",
      "locations": [
        {
          "line": 38,
          "column": 9
        }
      ],
      "path": [
        "users",
        "edges",
        1,
        "node",
        "verified"
      ]
    },
    {
      "message": "User has no status.",
      "locations": [
        {
          "line": 40,
          "column": 9
        }
      ],
      "path": [
        "users",
        "edges",
        1,
        "node",
        "secondaryEmail"
      ]
    },
    {
      "message": "User has no status.",
      "locations": [
        {
          "line": 37,
          "column": 9
        }
      ],
      "path": [
        "users",
        "edges",
        2,
        "node",
        "archived"
      ]
    },
    {
      "message": "User has no status.",
      "locations": [
        {
          "line": 38,
          "column": 9
        }
      ],
      "path": [
        "users",
        "edges",
        2,
        "node",
        "verified"
      ]
    },
    {
      "message": "User has no status.",
      "locations": [
        {
          "line": 40,
          "column": 9
        }
      ],
      "path": [
        "users",
        "edges",
        2,
        "node",
        "secondaryEmail"
      ]
    }
  ],
  "data": {
    "users": {
      "edges": [
        {
          "node": {
            "id": "VXNlck5vZGU6MQ==",
            "username": "admin",
            "archived": null,
            "verified": null,
            "email": "***",
            "secondaryEmail": null
          }
        },
        {
          "node": {
            "id": "VXNlck5vZGU6Mg==",
            "username": "mark",
            "archived": null,
            "verified": null,
            "email": "***",
            "secondaryEmail": null
          }
        },
        {
          "node": {
            "id": "VXNlck5vZGU6Mw==",
            "username": "user1",
            "archived": null,
            "verified": null,
            "email": "[email protected]",
            "secondaryEmail": null
          }
        },
        {
          "node": {
            "id": "VXNlck5vZGU6NA==",
            "username": "user2",
            "archived": false,
            "verified": true,
            "email": "[email protected]",
            "secondaryEmail": null
          }
        },
        {
          "node": {
            "id": "VXNlck5vZGU6NQ==",
            "username": "user3",
            "archived": true,
            "verified": true,
            "email": "[email protected]",
            "secondaryEmail": null
          }
        },
        {
          "node": {
            "id": "VXNlck5vZGU6Ng==",
            "username": "user4",
            "archived": false,
            "verified": true,
            "email": "[email protected]",
            "secondaryEmail": "[email protected]"
          }
        },
        {
          "node": {
            "id": "VXNlck5vZGU6Nw==",
            "username": "new",
            "archived": false,
            "verified": false,
            "email": "",
            "secondaryEmail": null
          }
        }
      ]
    }
  }
}

So both an error and a data response.
I already had two users and added the fixtures.

Note that I use a custom user table: users_user, which I have set in the settings as AUTH_USER_MODEL = "users.User". I also changed that in the users.json file.

Could you please help me to debug this?

Django management command to migrate existing users

We could add a django management command to handle user verification/status creation for old users when the dev team opts to use this package at mid-project. Also would be helpful having a specific flag for superuser and staff, making it easy to create a new staff or superuser without needing to verify by email or hardcoding on django shell.

v0.4

The new version of django-graphql-jwt (v0.3.1) is not compatible with the v0.3.X version of this package, so we need to release the v0.4.X.

Here is the difference from 0.3.0 to 0.3.1

Here is a suggestion of how to solve it.

Need maintainers

Please if you have the time and want to work on this package, all PRs are welcome!

Make it possible to specify the plain text email template

Prerequisites

  • Is it a bug?
  • Is it a new feature?
  • Is it a a question?
  • Can you reproduce the problem?
  • Are you running the latest version?
  • Did you check for similar issues?
  • Did you perform a cursory search?

For more information, see the CONTRIBUTING guide.

Description

Right now the plain text version of the email is generated on the fly, it would be nice to be able to use a plain text template.

User partial update?

Is there a good way to partially update the user?
I have my UPDATE_MUTATION_FIELDS defined like this

'UPDATE_MUTATION_FIELDS': ['email', 'username', 'nickname', 'profile_pic',
                                'first_name', 'last_name', 'date_of_birth'],

I want the client to able to update those fields one by one.
But when I ran such query:

mutation {
    updateAccount(username: "foo-bar"){
      errors
      success
    }
  }

Only the username field gets a value, all the other fields are set to empty string or None.
What is a good way to achieve it?

Feature / Idea: Use UserModel mixins to add UserStatus directly to a custom User model

Thank you for producing a great library with outstanding documentation.

The intention of this "issue" is to propose / discuss a different "design approach" of using mixins on a custom user model rather than the UserStatus OneToOneField.

This would work by putting all the functionality provided by UserStatus in to mixins of the form:

class VerifiedUserMixin(models.Model):
    verified = models.BooleanField(default=False)

    class Meta:
        abstract = True
    ...


class SecondaryEmailUserMixin(models.Model):
    secondary_email = models.EmailField(blank=True, null=True)

    class Meta:
        abstract = True
    ...

The mixin is then added to the custom user model in the project:

from django.contrib.auth.models import AbstractUser

from graphql_auth.mixins import VerifiedUserMixin


class CustomUser(VerifiedUserMixin, AbstractUser):

    email = models.EmailField(blank=False, max_length=254, verbose_name="email address")

    USERNAME_FIELD = "username"   # e.g: "username", "email"
    EMAIL_FIELD = "email"         # e.g: "email", "primary_email"

The main advantages are:

  • There is no need for an additional db table
  • All functionality is directly available from the CustomUser model (rather than via CustomUser.status). This reduces any opportunity of additional db queries when status is not select_related
  • It becomes easy to separate the different functionality and only include what is needed (in the example above I omitted the SecondaryEmailUserMixin from my CustomUser)
  • No need for signals to create the UserStatus instance

There is an added setup step of adding the mixins to the custom user model, but I am assuming the library is intended to be used with a custom user module so this is not a significant barrier

I realise this is quite a significant change, but in my experience adding functionality directly onto the user model is simpler to work with than related objects.

In principle the library could probably support both the 1-to-1 and mixin approach, but that would fairly significantly increase the maintenance overhead.

Customize error output

Hi,
This is just a question, is there an easy way to customize error output of mutations ? I would like it to be the same as the rest of my API
Because I tried quickly with inheritance and I got MRO errors.
Thanks !

Custom user model without username error with REGISTER_MUTATION_FIELDS

This app does not have username, but filling the first and last name is obligatory.
In settings.py I have:

GRAPHQL_AUTH = {
    'LOGIN_ALLOWED_FIELDS': ['email'],
    'REGISTER_MUTATION_FIELDS': ['email', 'first_name', 'last_name'],
    'REGISTER_MUTATION_FIELDS_OPTIONAL': [],
}

Graphql relay register mutation:

mutation {
  register(
    input: {
      email: "[email protected]",
      firstName: "Test3",
      lastName: "Last",
      password1: "supersecretpassword",
      password2: "supersecretpassword"
    }
  ) {
    success,
    errors,
    token,
    refreshToken
  }
}

Response:

{
  "errors": [
    {
      "message": "Please, enter valid credentials",
      "locations": [
        {
          "line": 2,
          "column": 3
        }
      ],
      "path": [
        "register"
      ]
    }
  ],
  "data": {
    "register": null
  }
}

Error from python console:

File "/home/bozho/.local/share/virtualenvs/server-WyGHa9Al/lib/python3.7/site-packages/graphql_jwt/decorators.py", line 91, in wrapper
    _('Please, enter valid credentials'))
graphql.error.located_error.GraphQLLocatedError: Please, enter valid credentials

Before the error the email is sent to the user. The user, however, is not created.
This can be either something improperly configured by me, or an error in the library.

Different id user query when I use info.context.user.id schema.py

Description

I have the different id user query when I use info.context.user.id schema.py.

Steps to Reproduce

  1. Create extend django user model
  2. Create schema
class Query(graphene.ObjectType):
    user = graphene.Field(UserType, token=graphene.String(required=True))

    @login_required
    def resolve_user(self, info, **kwargs):
        print(info.context.user.id, 'my user schema id')
        return info.context.user

  1. Create the example model (ex. Post)
  2. Create schema
class Query(graphene.ObjectType):
    post_partner = graphene.List(PostType)

    def resolve_post_partner(self, info):
        print(info.context.user.id, 'my user partner id')
        return Post.objects.order_by('-updated_at').filter(partner_id=info.context.user.id)
  1. Get query on graphQL. In the same time I have two query with id one is user model, second is example model. First I have correct ID, but the Post model I have None Id
    image
  1. When I log in app I use this mutation FRONTEND SIDE:

export const TOKEN_AUTH = gql`
  mutation tokenAuth($username:String!, $password: String!) {
    tokenAuth(username: $username, password: $password) {
      token,
      success,
      errors,
      unarchiving,
      user {
        id,
        username
      }
    }
  }
`;

async tokenAuth() {
      await this.$apollo.mutate({
        mutation: TOKEN_AUTH,
        variables: {
          username: this.username,
          password: this.account.password,
        }
      }).then(response => {
        if (response.data.tokenAuth.success) {
          const token = response.data.tokenAuth.token;
          this.$store.dispatch('user/setToken', token);
          this.verifyToken(token)
        } else {
          console.log(response.data.tokenAuth.errors.nonFieldErrors[0].message)
        }
      })
    },

Expected behavior

The same info.context.user.id in two query base the same info.

Actual behavior

Different, None or anonymous, but when I log i admin panel django I have the second query info.user.id -> id user who login i admin panel django

Requirements

aniso8601==7.0.0
Django==2.2.7
django-debug-toolbar==2.1
django-filter==2.2.0
django-webpack-loader==0.6.0
graphene==2.1.8
graphene-django==2.6.0
graphql-core==2.2.1
graphql-relay==2.0.0
promise==2.2.1
pytz==2019.3
Rx==1.6.1
singledispatch==3.4.0.3
six==1.13.0
sqlparse==0.3.0
redis==3.3.11
Pillow==6.2.1
djangorestframework==3.10.3
django-extensions==2.2.5
psycopg2==2.8.5
psycopg2-binary==2.7.6
six==1.13.0
sqlparse==0.3.0
celery==4.3.0
amqp==2.5.2
django-cors-headers==2.1.0
django-graphql-jwt==0.3.0
graphene-file-upload==1.2.2
django-graphql-auth==0.3.10
django-environ==0.4.5

Help using AbstractBaseUser

I want to overwrite the original django user model to custom user model with AbstractBaseUser. So, I can remove firstname, lastname etc field from the model. But it cause error like 'Unknown field(s)'. Are there any way to use AbstractBaseUser instead of AbstractUser for custom user with django-graphql-auth?

No specific error code for JWT errors

Prerequisites

  • Is it a bug?
  • [x ] Is it a new feature?
  • Is it a a question?
  • Can you reproduce the problem?
  • Are you running the latest version?
  • Did you check for similar issues?
  • Did you perform a cursory search?

For more information, see the CONTRIBUTING guide.

Description

When there is a JWT issue the error returned will be a HTTP code 200 and the error message won't have any specific error code that can be used to identify the issue without comparing the error message itself (bad idea)

It would be great if a 400 error code could be returned or a specific error type i.e "UNAUTHENTICATED" could be returned to identify this issue

Token and Refresh Token management

Hi, thanks for adding me as a collaborator in the project.

I understand that django-graphql-jwt is used in the backend as a way of handling authentication. Currently, I believe the library has issues handling refreshToken as a cookie. At the moment, in order to use refreshToken you will have to store it somewhere within the browser's session storage, this is vulnerable to XSS. A better option is to store the token as a httpOnly token. While this is still vulnerable to CSRF attacks, I believe Django does a good job at managing CSRF vulnerabilities.

The next issue with the library is that calling refreshToken generates a new refreshToken even if the token is not about to expire. This is wasteful and will quickly pollute the database with unnecessary data.

I believe the django-graphql-jwt library is not really ready for production usage. I have been trying to work on these problems in my fork. The maintainer of django-graphql-jwt is not really responsive. If you have any ideas to address this problem it would be fantastic.

Make django-graphql-auth use own salt

Currently the email tokens (e.g. for password reset) are created using django.signing and always with the same salt (django.core.signing). It would be wise to use specific salt for django-graphql-auth.

Found different types with the same name in the schema: ErrorType, ErrorType.

I have installed django-graphql-auth with the latest version of graphene-django, but I get the above error because of duplicate types with the same name. ErrorType in graphql_auth/types.py clashes with ErrorType in graphene_django/types.py. I want to use this package in a project, but this here is blocking me.

How to get more detailed logs?

When sending posting a mutation I get the following response:

Bad Request: /graphql
WARNING 2020-03-20 16:22:36,060 log 70927 123145500200960 Bad Request: /graphql
127.0.0.1 - - [20/Mar/2020 16:22:36] "POST /graphql HTTP/1.1" 400 -

Is there a way to get more detail?

Incompatible with django-graphql-jwt's cookie functionality

Description

The Django GraphQL JWT package supports storing JWT tokens in cookies and this effects among other things the refreshToken mutation by no longer requiring it as an argument (since the frontend JS is intentionally unable to access the token itself). Behind the scenes JWT presumably adds middleware or modifies existing classes to extract the token from passed Cookie headers. When using this Cookie configuration, django_graphql_auth won't work properly since it requires the refreshToken to be passed as an actual graphql argument.

Steps to Reproduce

If we need to reproduce and you don't provide steps for it, it will be closed. Alternatively, you can link a repo with the code to run your issue.

  1. Go through minimal setup of django_graphql_jwt and enable cookie authentication and various settings:
  1. Install django_graphql_auth
  2. Observe impossibility of passing refreshToken to the refreshToken mutation due to client no longer being able to access and pass along refreshToken since it is stored in cookie.

Expected behavior

I would expect that when django_graphql_jwt is configured to use cookies, django_graphql_auth would adjust it's mutations accordingly to extract the JWT from cookies in same manner django_graphql_jwt does.

Actual behavior

django_graphql_jwt generates mutations that cannot be used due to refreshToken not being able to be explicitly passed as a graphql mutation argument.

Requirements

django==3.0.6
django-graphql-jwt==0.3.1
graphene-django==2.9.1
django-graphql-auth==0.3.10

Send a signal when user is verified

Prerequisites

  • Is it a bug?
  • Is it a new feature?
  • Is it a a question?
  • Can you reproduce the problem?
  • Are you running the latest version?
  • Did you check for similar issues?
  • Did you perform a cursory search?

For more information, see the CONTRIBUTING guide.

Description

I would like to create a few extra model instances when the user is verified. The best way to do this is to listen to a signal that is sent when the user is verified.

Description of the bug/feature/question

Please add a signal that is sent when the user is verified.

last_login field does not updated

Description

I am using a token_auth mutation for login in my system.
When I check my User model in the database - last_login always is null.

Steps to Reproduce

  1. register new user via register mutation
  2. confirm user via verify_account
  3. get token via token_auth
  4. check the last_login field in the database

Expected behavior

I would like to see if the user gets a new token - last_login field updated to "now".

What happened

Nothing happened with last_login field

Requirements

django==3.0.5
graphene-django==2.10.1
django-graphql-jwt==0.3.0
django-graphql-auth=0.3.10

Add more data to email context

It would be useful to add more data to the email contexts. For example, password reset emails are often accompanied by (i) the request IP address and (ii) the timestamp of the request. These are then often displayed in the email - useful in the event of malicious intent.

Solution is easy: include (i) info.context and (ii) time.time() in get_email_context.

Happy to shoot across a PR for this.

Not Authenticate user in other query

Hello I have problem with authenticate. At first i called "me" query i got null user. At second i wrote one authentication backend and me query fixed but when i write one query and inside it use info.context.user i get Anonymous user. when i debug it the code never go to backend authentication but in me query gone.

Somethings that i have done but not fixed:

  1. delete my backend authentication
  2. change graphql_auth.backends.GraphQLAuthBackend to
    graphql_jwt.backends.JSONWebTokenBackend(but i got this error "User is disabled": graphql.error.located_error.GraphQLLocatedError: User is disabled)

With these codes me query work well but own query not

MyCustom User:

class MyUser(AbstractBaseUser, PermissionsMixin):
    email = models.EmailField(unique=True)
    is_man = models.BooleanField(default=True)
    user_type = models.CharField(max_length=3, choices=USER_TYPE_CHOICES, default='STD')
    phone_number = models.CharField(max_length=11, unique=True)
    first_name = models.CharField(max_length=50)
    last_name = models.CharField(max_length=50)
    is_active = models.BooleanField(default=False)
    username = None
    objects = UserManager()
    USERNAME_FIELD = 'email'
    EMAIL_FIELD = 'email'
    REQUIRED_FIELDS = ['phone_number']

    def __str__(self):
        return self.email 

MyCustom UserManager :

 class UserManager(BaseUserManager):
    use_in_migrations = True

    def create_user(self, email, is_man, is_student, phone_number, first_name, last_name, password=None):
        if not email:
            raise ValueError('Email is not provided.')

        user = self.model(
            email=email,
            is_man=is_man,
            phone_number=phone_number,
            first_name=first_name,
            last_name=last_name
        )

        user.set_password(password)
        user.save(using=self.db)

        return user

    def create_superuser(self, email, password, **extra_fields):
        """
        Create and save a SuperUser with the given email and password.
        """
        extra_fields.setdefault('is_staff', True)
        extra_fields.setdefault('is_superuser', True)
        extra_fields.setdefault('is_active', True)

        if extra_fields.get('is_staff') is not True:
            raise ValueError(_('Superuser must have is_staff=True.'))
        if extra_fields.get('is_superuser') is not True:
            raise ValueError(_('Superuser must have is_superuser=True.'))
        return self.create_user(email, password, **extra_fields) 

My Custom Authentication Backend :

 class EmailBackend:
    def authenticate(request, username=None, password=None):
        if username is not None:
            user_model = get_user_model()

            try:
                user = user_model.objects.get(email__iexact=username)
            except user_model.DoesNotExist:
                """Not found, try another backend"""
            else:
                if user.check_password(password):
                    return user
        if request.user is not None:
            user_model = get_user_model()
            try:
                token = request.headers._store['authorization'][1][4:]
                play_load = get_payload(token=token)
                user = user_model.objects.get(email__iexact=play_load['email'])
                return user
            except user_model.DoesNotExist:
                """Not found, try another backend"""
        return None

My Own Qury :

class UsersQuery(graphene.ObjectType):
    student = graphene.relay.Node.Field(StudentNode)
    all_students = DjangoFilterConnectionField(StudentNode)

    def resolve_all_students(self, info, **kwargs):
        if not info.context.user.is_authenticated:
            raise ObjectDoesNotExist

My settings:

AUTHENTICATION_BACKENDS = [
    "graphql_auth.backends.GraphQLAuthBackend",
    'users.models.EmailBackend',
]
GRAPHENE = {
    'SCHEMA': 'dormify.schema.schema',
    'MIDDLEWARE': [
        'graphql_jwt.middleware.JSONWebTokenMiddleware',
    ],
}
GRAPHQL_AUTH = {
    'LOGIN_ALLOWED_FIELDS': ['email'],
    'ALLOW_LOGIN_NOT_VERIFIED': True,  # Change This to false to add email confirmation
    'ALLOW_LOGIN_WITH_SECONDARY_EMAIL': False,
    'REGISTER_MUTATION_FIELDS': {
        "email": "String",
        "is_man": "Boolean",
        "user_type": "String",
        "phone_number": "String",
        "first_name": "String",
        "last_name": "String"
    },
    'USER_NODE_FILTER_FIELDS': {
        "email": ["exact", ],
        "first_name": ["exact", "icontains", "istartswith"],
        "last_name": ["exact", "icontains", "istartswith"],
        "is_active": ["exact"],
        "user_type": ["exact"],
    },
    'USER_NODE_EXCLUDE_FIELDS': ["is_superuser", "password"],
    'EMAIL_SUBJECT_ACTIVATION': "email/activation_subject.txt",
    'EMAIL_SUBJECT_ACTIVATION_RESEND': "email/activation_subject.txt",
    'EMAIL_SUBJECT_PASSWORD_RESET': "email/password_reset_subject.txt",
    'EMAIL_TEMPLATE_ACTIVATION': "email/activation_email.html",
    'EMAIL_TEMPLATE_ACTIVATION_RESEND': "email/activation_email.html",
    'EMAIL_TEMPLATE_PASSWORD_RESET': "email/password_reset_email.html",
}
GRAPHQL_JWT = {
    "JWT_VERIFY_EXPIRATION": True,
    'JWT_EXPIRATION_DELTA': timedelta(minutes=60),
    'JWT_REFRESH_EXPIRATION_DELTA': timedelta(days=7),
    # optional
    "JWT_LONG_RUNNING_REFRESH_TOKEN": True,
    "JWT_ALLOW_ANY_CLASSES": [
        "graphql_auth.relay.Register",
        "graphql_auth.relay.VerifyAccount",
        "graphql_auth.relay.ResendActivationEmail",
        "graphql_auth.relay.SendPasswordResetEmail",
        "graphql_auth.relay.PasswordReset",
        "graphql_auth.relay.ObtainJSONWebToken",
        "graphql_auth.relay.VerifyToken",
        "graphql_auth.relay.RefreshToken",
        "graphql_auth.relay.RevokeToken",
        "graphql_auth.relay.VerifySecondaryEmail",
    ],
}

Add "me" query

It would be useful to have a "me" query where the client gets the details of the logged-in user (sending a JWT). The client doesn't have to store the ID in that case.

This could be done with something like this I think:

def resolve_me(self, info):
  user = info.context.user
  if user.is_anonymous:
    raise GraphQLError('Not logged in!')

What do you think?

Async email support

Currently, all emails are sent in the mixins.py but would be great to have async support.

I think the easiest way to make an optional plug and play support would be creating a new setting to enter a function that wraps each send email call.

Actually it's not an async email support, but make easy to integrate with your own async solution.

# settings
EMAIL_ASYNC_TASK = None

Then it accepts a function path"

EMAIL_ASYNC_TASK: "path/to/task"

The task need to accept the email send function and its arguments, usage with celery would be something like this:

from celery import task
 
@task
def graphql_auth_async_email(func, *args):
    """
    Task to send an e-mail for the graphql_auth package
    """
 
    return func(*args)

Then, in the mixins.py, we need to change all send email calls, for example:

# from
user.status.send_activation_email(info)

# to
if app_settings.EMAIL_ASYNC_TASK:
    app_settings.EMAIL_ASYNC_TASK(user.status.send_activation_email, info)
else:
    user.status.send_activation_email(info)

Of course, to make this work we must import the function from its path in the settings.py, probably using:

from django.utils.module_loading import import_string

Protect graphene django "auto" queries and mutations

Prerequisites

  • Is it a bug?
  • Is it a new feature?
  • [ โœ…] Is it a a question?
  • Can you reproduce the problem?
  • Are you running the latest version?
  • Did you check for similar issues?
  • Did you perform a cursory search?

Description

Hi, nice work.

I'm trying to private graphene django auto queries and mutations. "Auto" means queries with DjangoObjectType and DjangoFilterConnectionField, and mutations with DjangoModelFormMutation and DjangoFormMutation

The @login_required decorator in graphql_jwt package does not works if resolve method does not exist.

Can't exclude user node field "secondaryEmail" using USER_NODE_EXCLUDE_FIELDS

Prerequisites

  • Is it a bug?
  • Is it a new feature?
  • Is it a a question?
  • Can you reproduce the problem?
  • Are you running the latest version?
  • Did you check for similar issues?
  • Did you perform a cursory search?

Description

I have tried using USER_NODE_EXCLUDE_FIELDS to exclude secondaryEmail however, since secondaryEmail is resolved it doen't seem possible to excluded it in this way.

Is there another mechanism to exclude these fields. My assumption is that I need to (re)create my own UserNode along with the MeQuery and UserQuery

Custom user model configuration

Prerequisites

  • Is it a bug?
  • Is it a new feature?
  • Is it a a question?
  • Can you reproduce the problem?
  • Are you running the latest version?
  • Did you check for similar issues?
  • Did you perform a cursory search?

For more information, see the CONTRIBUTING guide.

Description

Is it on purpose that one is not able to resolve a user from a custom Django model (called 'Component' in my case) that is related to a user via a ForeignKey? When I try to query the user field (called 'creator' in my case) I receive the following error message: "Cannot query field "creator" on type "ComponentNode""
The issue originates from the usage of the seemingly undocumented Meta property 'skip_registry' of graphenes 'DjangoObjectType' in the definition of the UserNode class.
What is the reason and purpose for setting 'skip_registry' to True?

Expected behavior

Access non-critical user properties (like username and id) from related objects

Actual behavior

The relation between a custom Django model and a user is not resolved from a graphql query to the custom model

Email didnt validate upon registration when it's empty

settings.py
GRAPHQL_AUTH = {
'LOGIN_ALLOWED_FIELDS': ['email', 'username'],
'ALLOW_LOGIN_NOT_VERIFIED': False,
'REGISTER_MUTATION_FIELDS': ['email', 'username', 'first_name', 'last_name'],
'UPDATE_MUTATION_FIELDS': ['first_name', 'last_name']
# ...
}

#registration
mutation { register( email: "", username: "as", password1: "Pasmo.123", password2: "Pasmo.123", first_name: "wawex", last_name: "wawex" ) { success, errors, # token } }
#response
{ "data": { "register": { "success": true, "errors": null } } }

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.