Skip to content

Installation


Requirements

  • Python: 3.10 - 3.11
  • Django: 3.2 - 4.2 - 5.0

Installation

pip install django-graphene-auth

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.


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. Get user handler for Authentication Backend

Add to GRAPHQL_JWT['JWT_GET_USER_BY_NATURAL_KEY_HANDLER'] setting for joining user status to Django request.user by using select_related("status") in the query.:

GRAPHQL_JWT = {
    # ...
    "JWT_GET_USER_BY_NATURAL_KEY_HANDLER": "graphql_auth.utils.get_user_by_natural_key",
    # ...
}

4. Authentication Backend - optional

Add the following to your AUTHENTICATION_BACKENDS:

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

    # add 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 behavior?

Instead 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:


5. Refresh Token - optional

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

Follow the official 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

6. 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,
    },
]

7. 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.