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.7.tar.gz (14.6 kB view details)

Uploaded Source

Built Distribution

ariadne_jwt-0.1.7-py2.py3-none-any.whl (19.0 kB view details)

Uploaded Python 2 Python 3

File details

Details for the file ariadne-jwt-0.1.7.tar.gz.

File metadata

  • Download URL: ariadne-jwt-0.1.7.tar.gz
  • Upload date:
  • Size: 14.6 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/3.2.0 pkginfo/1.5.0.1 requests/2.24.0 setuptools/49.2.1.post20200807 requests-toolbelt/0.9.1 tqdm/4.48.2 CPython/3.7.7

File hashes

Hashes for ariadne-jwt-0.1.7.tar.gz
Algorithm Hash digest
SHA256 4e5082af612fc4995f0771b3e26e380210979c8401b6a882903c96d4d41a8492
MD5 3e2ea147b262b8b34be7ab76d293f33d
BLAKE2b-256 21bde4a1c88880e441bce18068eb920b7552185150f6b7c7ebbd57ba58ad4214

See more details on using hashes here.

File details

Details for the file ariadne_jwt-0.1.7-py2.py3-none-any.whl.

File metadata

  • Download URL: ariadne_jwt-0.1.7-py2.py3-none-any.whl
  • Upload date:
  • Size: 19.0 kB
  • Tags: Python 2, Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/3.2.0 pkginfo/1.5.0.1 requests/2.24.0 setuptools/49.2.1.post20200807 requests-toolbelt/0.9.1 tqdm/4.48.2 CPython/3.7.7

File hashes

Hashes for ariadne_jwt-0.1.7-py2.py3-none-any.whl
Algorithm Hash digest
SHA256 4aa42050bf5b9d3b6394e867cfbc288d831596d2fe6db17e39aaff4a7fb9cf10
MD5 b991bc138c157abfe72b9c20dc4c9382
BLAKE2b-256 c8cd44273777235d7afe51c8e868eb9e770c43c2755bcd64053869ee697b35d1

See more details on using hashes here.

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