Skip to main content

JSON Web Token for Ariadne Django

Project description

Ariadne JWT

JSON Web Token for Ariadne Django

Installation

pip install ariadne-jwt

Include the JSONWebTokenMiddleware in your MIDDLEWARE settings:

MIDDLEWARE = [
    'django.contrib.auth.middleware.AuthenticationMiddleware',
    'ariadne_jwt.middleware.JSONWebTokenMiddleware',
]

Include the JSONWebTokenBackend in your AUTHENTICATION_BACKENDS settings:

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

Schema

Add mutations to your GraphQL schema

import ariadne
from ariadne_jwt import resolve_verify, resolve_refresh, resolve_token_auth, jwt_schema, GenericScalar

type_defs = '''
    type Mutation {
        ...
        verifyToken(token: String!): VerifyToken
        refreshToken(token: String!): RefreshToken
        tokenAuth(username: String!, password:String!): TokenAuth
        ...
    }
    '''

mutation = ariadne.MutationType()

mutation.set_field('verifyToken', resolve_verify)
mutation.set_field('refreshToken', resolve_refresh)
mutation.set_field('tokenAuth', resolve_token_auth)

schema = ariadne.make_executable_schema([type_defs, jwt_schema], mutation, GenericScalar)
  • tokenAuth to authenticate the user and obtain the JSON Web Token.

The resolver uses User's model USERNAME_FIELD_, which by default is username.

mutation TokenAuth($username: String!, $password: String!) {
    tokenAuth(username: $username, password: $password) {
        token
    }
}
  • verifyToken to confirm that the token is valid.
mutation VerifyToken($token:String!) {
    verifyToken(token: $token) {
        payload
    }
}
  • refreshToken to obtain a brand new token with renewed expiration time for non-expired tokens.
mutation RefreshToken($token: String!) {
    refreshToken(token: $token) {
        token
        payload
    }
}

Authentication in GraphQL queries

Now in order to access protected API you must include the Authorization: JWT <token> header. you can use the login_required() decorator for your resolvers:

from ariadne import QueryType
from ariadne_jwt.decorators import login_required

type_defs = '''
type UserNode {
    username:String
    email: String
}
type Query {
    me: UserNode
}
'''

query = QueryType()


@query.field('me')
@login_required
def resolve_viewer(self, info, **kwargs):
    return info.context.get('request').user

Customizing

If you want to customize the tokenAuth behavior, you'll need to extend the TokenAuth type and write a resolver with @token_auth decorator.

from ariadne_jwt.decorators import token_auth

extended_type_defs = '''
type UserNode {
    id
    username
    email
}
extend type TokenAuth {
    user: UserNode
}
'''


@token_auth
def resolve_token_auth(obj, info, **kwargs):
    return {'user': info.context.get('request').user}
mutation TokenAuth($username: String!, $password: String!) {
    tokenAuth(username: $username, password: $password) {
        token
        user {
            id
        }
    }
}

Settings

ariadne-jwt reads your configuration from a single Django setting named GRAPHQL_JWT

GRAPHQL_JWT = {
    'JWT_VERIFY_EXPIRATION': True,
    'JWT_EXPIRATION_DELTA': timedelta(seconds=60 * 10)
}

Default Settings

DEFAULTS = {
    # Algorithm for cryptographic signing
    'JWT_ALGORITHM': 'HS256',

    # Identifies the recipients that the JWT is intended for
    'JWT_AUDIENCE': None,

    # Identifies the principal that issued the JWT
    'JWT_ISSUER': None,

    # Validate an expiration time which is in the past but not very far
    'JWT_LEEWAY': 0,

    # The secret key used to sign the JWT
    'JWT_SECRET_KEY': settings.SECRET_KEY,

    # Secret key verification
    'JWT_VERIFY': True,

    # Expiration time verification
    'JWT_VERIFY_EXPIRATION': False,

    # Timedelta added to utcnow() to set the expiration time
    'JWT_EXPIRATION_DELTA': timedelta(seconds=60 * 5),

    # Enable token refresh
    'JWT_ALLOW_REFRESH': True,

    # Limit on token refresh
    'JWT_REFRESH_EXPIRATION_DELTA': timedelta(days=7),

    # Enable long time running refresh token
    'JWT_LONG_RUNNING_REFRESH_TOKEN': False,

    # The model to use to represent a refresh token
    'JWT_REFRESH_TOKEN_MODEL': 'refresh_token.RefreshToken',

    # Refresh token number of bytes
    'JWT_REFRESH_TOKEN_N_BYTES': 20,

    # Authorization header name
    'JWT_AUTH_HEADER': 'HTTP_AUTHORIZATION',

    # Authorization prefix
    'JWT_AUTH_HEADER_PREFIX': 'JWT',

    # A custom function *f(payload, context)* to encode the token
    'JWT_ENCODE_HANDLER': 'ariadne_jwt.utils.jwt_encode',

    # A custom function *f(token, context)* to decode the token
    'JWT_DECODE_HANDLER': 'ariadne_jwt.utils.jwt_decode',

    # A custom function *f(user, context)* to generate the token payload
    'JWT_PAYLOAD_HANDLER': 'ariadne_jwt.utils.jwt_payload',

    # A custom function `f(payload)` to obtain the username    
    'JWT_PAYLOAD_GET_USERNAME_HANDLER': (lambda payload: payload.get(get_user_model().USERNAME_FIELD)),

    # A custom function `f(orig_iat, context)` to determine if refresh has expired
    'JWT_REFRESH_EXPIRED_HANDLER': 'ariadne_jwt.utils.refresh_has_expired',
}

Writing tests

from django.contrib.auth import get_user_model
from ariadne_jwt.testcases import JSONWebTokenTestCase


class UserTests(JSONWebTokenTestCase):
    def setUp(self):
        self.user = get_user_model().objects.create_user(username='test', password='dolphins')
        self.client.authenticate(self.user)
        self.client.schema(type_defs, resolvers, directives=directives)

    def test_get_user(self):
        query = '''
            query GetUser($username: String) {
                user(username: $username) {
                    id
                }
            }
            '''
        self.client.execute(query, variables={'username': self.user.username})

Testing the library

run the following in root directory

python run_tests.py

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

ariadne-jwt-0.1.5.tar.gz (14.6 kB view hashes)

Uploaded Source

Built Distribution

ariadne_jwt-0.1.5-py2.py3-none-any.whl (19.0 kB view hashes)

Uploaded Python 2 Python 3

Supported by

AWS AWS Cloud computing and Security Sponsor Datadog Datadog Monitoring Fastly Fastly CDN Google Google Download Analytics Microsoft Microsoft PSF Sponsor Pingdom Pingdom Monitoring Sentry Sentry Error logging StatusPage StatusPage Status page