Crypto Keypair Authorization for Django Rest Framework
This Django module was created to give "Cavage" HTTP Signatures capabilities to the Django Rest Framework.
This enables HTTP authorization based on public key/private key encryption as an alternative to session cookies or API tokens.
In your Django code, it looks like this:
from keypair_permissions.permissions import HasHttpCryptoAuthorization
class EchoServerApiView(GenericApiView):
permission_classes = [HasHttpCryptoAuthorization]
def get(self, request):
return Response(request.body)
Doing so will require an Authorization
HTTP header that looks like this:
HTTP/1.1 POST /foo
Authorization: Signature algorithm="hs2019",keyId="keyname",signature="MEUCIGGB0P3P/iZCzCbX1fj1Q6AbYPJr9dEBYcsuiLoS3q6uAiEAkEjvmWfuN1UDPmYCkBywnI/MwisCuNEmlAxPB3ZBVgc="
... other headers ...
This authorization header is created by signing Request headers with a private key on the client. The server then verifies the Request was sent by a known client by verifying the signature using the client's public key.
Additionally, a Digest
header can be added to ensure the Request body was transported in tact:
Digest: SHA512=WZDPaVn/7XgHaAy8pmojAkGWoRx2UFChF41A2svX+TaPm+AbwAgBWnrIiYllu7BNNyealdVLvRwEmTHWXvJwew==
Each public key can be associated with a Django User, so the User can be accessed from the View:
class EchoServerApiView(GenericApiView):
permission_classes = [HasHttpCryptoAuthorization]
def get(self, request):
user = request.public_key.user
return Response(request.body)
For more information see Draft Cavage HTTP Signatures 12
Quickstart
Install:
$ pip install drf-keypair-permissions
Add keypair_permissions
to your settings.INSTALLED_APPS
:
settings.py
:
INSTALLED_APPS = [
...
'keypair_permissions',
]
Migrate the database
$ ./manage.py makemigrations
$ ./manage.py migrate
Include to your project
views.py
:
from keypair_permissions.permissions import HasHttpCryptoAuthorization
Set the permission_classes
of API views to include HasHttpCryptoAuthorization
:
class EchoServerApiView(GenericApiView):
permission_classes = [HasHttpCryptoAuthorization]
def get(self, request):
return Response(request.body)
Or use across your entire API by setting REST_FRAMEWORK['DEFAULT_PERMISSION_CLASSES']
:
REST_FRAMEWORK = {
'DEFAULT_PERMISSION_CLASSES': [
'keypair_permissions.permissions.HasHttpCryptoAuthorization',
]
}