Skip to content

aaronlelevier/django-rest-framework-hmac

Repository files navigation

Django REST Framework HMAC Authentication

This library implements the HMAC Authentication protocol for the django-rest-framework.

This is useful because HMAC allows the client to authenticate and make an http request at the same time.

HMAC is used by the botocore Python library by AWS and other places around the web.

Requirements

  • Python 3.6
  • Django 2.0+
  • Django REST Framework 3.7

Installation

Install using pip...

$ pip install django-rest-framework-hmac

Documentation

How to use

Define a View with HMACAuthentication set in the authentication_classes

from rest_framework.views import APIView
from rest_framework_hmac.authentication import HMACAuthentication

class MyView(APIView):
    authentication_classes = (HMACAuthentication,)

Register the HMACKey Signal, so a HMAC key and secret get generated each time a User is created.

from django.conf import settings
from django.db.models.signals import post_save
from django.dispatch import receiver
from rest_framework_hmac.hmac_key.models import HMACKey

@receiver(post_save, sender=settings.AUTH_USER_MODEL)
def create_hmac_key(sender, instance=None, created=False, **kwargs):
    if created:
        HMACKey.objects.create(user=instance)

Use the above relationship between the Django User and HMACKey Model with the HMACSigner convenience class to generate a HMAC signed request.

To successfully make a request to this View, the client must set 3 properties in the request header:

  • Key
  • Signature
  • Timestamp

The Key is used to lookup the Django User

The Signature is the HMAC Signature generated by signing with the HMAC cryptographic key

The Timestamp can be any string timestamp. In the example the HMACSigner the timestamp is ISO8601

import time

from rest_framework.test import APIClient
from rest_framework_hmac.client import HMACSigner
from django.contrib.auth.models import User

# generate the signature using the headers and request
# payload if present
ISO8601 = '%Y-%m-%dT%H:%M:%SZ'
TIME = time.strftime(ISO8601, time.gmtime())
user = User.objects.create_user('bob')

hmac_signer = HMACSigner(user)
headers = {
    'method': POST,
    'hostname': '127.0.0.1',
    'path': '/',
    'timestamp': TIME
}
post_data = {'title': 'new idea'}
signature = hmac_signer.calc_signature(headers, post_data)

# Make request with all required headers
client = APIClient()
headers = {
    'Key': user.hmac_key.key,
    'Signature': signature,
    'Timestamp': TIME
}
client.post('/notes/', post_data, format='json', **headers)

Example project

To run the example project, run the following commands

cd rest_framework_hmac/example_project/

# create virtualenv (python3 must be installed)
python3 -m venv venv

# activate virtualenv
source venv/bin/activate

# install requirements
pip install -r requirements.txt

cd example

# run tests
./manage.py test

# or run Django local server
./manage.py runserver

License

BSD 2-Clause