In all most every project we need user authentication. Django has session-based built-in user authentication and authorization support. But in modern days most of our applications are stateless, so, we are covering here stateless user authentication with JWT.

If you are following our previous articles, you already created a blog app with Graphene-Django. We did not add user authentication for our blog app. Here we will use django-graphql-jwt with Graphene-Django.

Let’s do some basic setup.

Basic Setup

Create a new app called account with the following command.

python manage.py startapp account

Now update INSTALLED_APPS with account app in morning_blog/settings.py as following.

INSTALLED_APPS = [
     # ...
    'account',
    'blog',
]

Cool! Install django-graphql-jwt with the following command.

pip install django-graphql-jwt

Update  GRAPHENE settings with JSONWebTokenMiddleware middleware as following.

GRAPHENE = {
    "SCHEMA": "morning_blog.schema.schema",
    'MIDDLEWARE': [
        'graphql_jwt.middleware.JSONWebTokenMiddleware',
    ],
}

And Add AUTHENTICATION_BACKENDS in the settings.py as following.

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

Now create a directory inside account app called schema and add a file called users.py. Your folder structure should look like this-

Django-Graphene authentication folder structure

Go to account/schema/users.py file and add the following codes.

import graphene
import graphql_jwt
from graphene_django.types import DjangoObjectType, ObjectType

from django.contrib.auth import get_user_model


User = get_user_model()

User Types

Let’s define some types for the User model. Add the following codes to account/schema/users.py file.

class UserFields:
    username = graphene.String(required=True)
    password = graphene.String(required=True)
    email = graphene.String(required=True)


class UserType(DjangoObjectType, UserFields):
    class Meta:
        model = User


class UserInputType(graphene.InputObjectType, UserFields):
    id = graphene.ID()

User Schema

Add the following schema for queries and mutations.

class Query(ObjectType):
    me = graphene.Field(UserType)
    users = graphene.List(UserType)

    def resolve_me(self, info, **kwargs):
        user = info.context.user
        if user.is_anonymous:
            raise Exception('Please login!')
        return user

    def resolve_users(self, info, **kwargs):
        return User.objects.all()    


class CreateUser(graphene.Mutation):
    class Arguments:
        input = UserInputType(required=True)

    ok = graphene.Boolean()
    user = graphene.Field(UserType)
    
    @staticmethod
    def mutate(root, info, input):
        user = User()
        for key, val in input.items():
            setattr(user, key, val)
        user.set_password(input.password)    
        user.save()
        return CreateUser(ok=True, user=user)


class Mutation(graphene.ObjectType):
    create_user = CreateUser.Field()
    token_auth = graphql_jwt.ObtainJSONWebToken.Field()
    verify_token = graphql_jwt.Verify.Field()
    refresh_token = graphql_jwt.Refresh.Field()

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

And update morning_blog/schema.py with the following code.

from account.schema.users import schema as user_schema 


class Query(author_schema.Query, blog_schema.Query, user_schema.Query):
    pass


class Mutation(author_schema.Mutation, blog_schema.Mutation, user_schema.Mutation):
    pass

We are done. Awesome. Let’s test the authentication API.

Test User Authentication

To test the API open Graphiql in your browser. Here we have to create a new user first. To create a new user add the following code to Graphiql console and run it.

mutation createUser {
  createUser(input: {
   username: "ijhar1",
   email: "ijharislam@gmail.com",
   password: "morning_blog"
  }) {
    ok
    user {
      id
      username
      email
    }
  }
}

You should see the following result.

{
  "data": {
    "createUser": {
      "ok": true,
      "user": {
        "id": "2",
        "username": "ijhar1",
        "email": "ijharislam@gmail.com"
      }
    }
  }
}

To get the JWT token, add the following mutation to the console.

mutation  {
  tokenAuth(username:"ijhar1", password: "morning_blog") {
    token
  }
}

You will see the following result.

{
  "data": {
    "tokenAuth": {
      "token": "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJ1c2VybmFtZSI6ImlqaGFyMSIsImV4cCI6MTU3ODM4MjE1NSwib3JpZ0lhdCI6MTU3ODM4MTg1NX0.12feFRinT44DB1dgaW16T_cTCB9PDV_30EmpuUYQBwY"
    }
  }
}

We may need to verify the token. To verify it, add the following code to the console.

mutation  {
  verifyToken(token:"eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJ1c2VybmFtZSI6ImlqaGFyMSIsImV4cCI6MTU3ODM4MjE1NSwib3JpZ0lhdCI6MTU3ODM4MTg1NX0.12feFRinT44DB1dgaW16T_cTCB9PDV_30EmpuUYQBwY") {
    payload
  }
}

You should see the following result.

{
  "data": {
    "verifyToken": {
      "payload": {
        "username": "ijhar1",
        "exp": 1578382155,
        "origIat": 1578381855
      }
    }
  }
}

To refresh the token, we can use the following mutation.

mutation  {
  refreshToken(token:"eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJ1c2VybmFtZSI6ImlqaGFyMSIsImV4cCI6MTU3ODM4MjE1NSwib3JpZ0lhdCI6MTU3ODM4MTg1NX0.12feFRinT44DB1dgaW16T_cTCB9PDV_30EmpuUYQBwY") {
    payload
  }
}

It will return the following result.

Conclusion

User authentication is the foundation of any online business. JWT (JSON Web Token) is a very popular stateless token-based authentication tool. To implement token-based authentication with GraphQL and Django, we used django-graphql-jwt

If you would like to see the full source code, check it out from here.