Installation

Attention

If you are not familiarized with Graphene or GraphQL JWT, skip this installation section and go to the quickstart guide.


Requirements

  • Python: 3.6 - 3.7 - 3.8
  • Django: 2.1 - 2.2 - 3.0

Installation

pip install django-graphql-auth

For those that are not installed, this will automatically install graphene, graphene-django, django-graphql-jwt, django-filter and django.

Add graphql_auth to installed apps.

INSTALLED_APPS = [
    # ...
    "graphql_auth"
]

Migrate:

python manage.py migrate

Setup

The following are the minimum steps required to get it running. It should not take more than 10 minutes.


1. Schema

In your schema, add the following:

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)
import graphene

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

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

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


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


class Mutation(AuthRelayMutation, graphene.ObjectType):
    pass


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

2. Allow Any Classes

On your GRAPHQL_JWT["JWT_ALLOW_ANY_CLASSES"] setting, add the following:

GRAPHQL_JWT = {
    #...
    "JWT_ALLOW_ANY_CLASSES": [
        "graphql_auth.mutations.Register",
        "graphql_auth.mutations.VerifyAccount",
        "graphql_auth.mutations.ResendActivationEmail",
        "graphql_auth.mutations.SendPasswordResetEmail",
        "graphql_auth.mutations.PasswordReset",
        "graphql_auth.mutations.ObtainJSONWebToken",
        "graphql_auth.mutations.VerifyToken",
        "graphql_auth.mutations.RefreshToken",
        "graphql_auth.mutations.RevokeToken",
        "graphql_auth.mutations.VerifySecondaryEmail",
    ],
}
GRAPHQL_JWT = {
    #...
    "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",
    ],
}

3. Authentication Backend - optional

Add the following to your AUTHENTICATION_BACKENDS:

AUTHENTICATION_BACKENDS = [
    # remove this
    # "graphql_jwt.backends.JSONWebTokenBackend",

    # add this
    "graphql_auth.backends.GraphQLAuthBackend",

    # ...
]

What's the difference from the graphql_jwt.backend?

We implement the same backend with only one difference:

  • It will not raise if you send a request with bad token to a class that is not on JWT_ALLOW_ANY_CLASSES.

Why should I want this behaivor?

Intead of raising an actual error, we can handle it and return whatever make sense, e.g.:

  cls(success=False errors="Unauthenticated.")


You should handle this situation doing one of the following:


4. Refresh Token - optional

Refresh tokens are optional and this package will work with the default token from Django GraphQL JWT.

Follow the offitial docs or simply add the following to your settings.py:

INSTALLED_APPS = [
    # ...
    'graphql_jwt.refresh_token.apps.RefreshTokenConfig'
]

GRAPHQL_JWT = {
    # ...
    'JWT_VERIFY_EXPIRATION': True,
    'JWT_LONG_RUNNING_REFRESH_TOKEN': True,
}

And remember to migrate:

python manage.py migrate

5. Email Templates

Overriding email templates is covered here.

This package comes with some default email templates, if you plan to use it, make sure your templates configuration has the following:

TEMPLATES = [
    {
        # ...
        'APP_DIRS': True,
    },
]

6. Email Backend

The default configuration is to send activation email, you can set it to False on your settings, but you still need an Email Backend to password reset.

The quickest way for development is to setup a Console Email Backend, simply add the following to your settings.py.

EMAIL_BACKEND = 'django.core.mail.backends.console.EmailBackend'

Now all emails are sent to the standard output, instead of an actual email.