How can i make django-rest-framework-jwt return token on registration?

diwakarb picture diwakarb · Jun 30, 2015 · Viewed 11.8k times · Source

I have a basic django rest service, which

  1. registers a person and
  2. updates his password.

I want to add jwt authentication on top of it. If I follow the tutorial I would need to add a new url named "api-token-auth" in project's urls.py. But, I don't want to add this new url and want my register call to send a token in response.

Here's my code:

serializers.py

class UserSerializer(serializers.HyperlinkedModelSerializer):
    def create(self, validated_data):
        user = User(
            username=validated_data['username']
        )
        user.set_password(validated_data['password'])
        user.save()
        return user

    def update(self, instance, validated_data):
        instance.set_password(validated_data['password'])
        instance.save()
        return instance

    class Meta:
        model = User
        fields = ('url', 'username', 'password')
        lookup_field = 'username'
        write_only_fields = ('password',)

views.py

class UserViewSet(viewsets.ModelViewSet):
    """
    API endpoint that allows users to be viewed or edited.
    """
    queryset = User.objects.exclude(is_superuser=1)
    serializer_class = UserSerializer
    lookup_field = 'username'
  1. What should be done to achieve this ? should I call api-auth-token inside my serializer's create method ?
  2. How does django-rest-framework-jwt handles multiple authentication tokens and correctly identifies which token belongs to which user ? Especially when it doesn't store tokens in a db.
  3. How can I use this authentication mechanism to limit my user to view/update/delete only his user ?
  4. How can I use this authentication mechanism to do anything in general. For instance if a user wants to write his name to /tmp/abcd.txt. How can I make sure that only authenticated users would be able to do so ?
  5. Are there any potential loopholes in this approach. Should I use the same code if my app is going to store lots of classified data ?

Answer

James Muranga picture James Muranga · Jul 1, 2015

Question 1: To generate tokens manually on registration you can define and make use of a method like this:

import jwt
from rest_framework_jwt.utils import jwt_payload_handler

def create_token(user):
    payload = jwt_payload_handler(user)
    token = jwt.encode(payload, settings.SECRET_KEY)
    return token.decode('unicode_escape')

you can add this method to the view and generate the token once the user has been registered and return it in the response.

Question 2: JWT tokens do not need to be stored in the database. You can read more about how JWT works at http://jwt.io/.

Question 3 and 4: To use tokens to limit access to a specific view, especially an APIView or one of its subclasses or a view provided by Django Rest framework, you need to specify the permission classes. for example:

from rest_framework.permissions import IsAuthenticated
from rest_framework.response import Response
from rest_framework.views import APIView

class ExampleView(APIView):
    permission_classes = (IsAuthenticated,)

    def get(self, request, format=None):
        content = {
            'status': 'request was permitted'
        }
        return Response(content)

Question 5: One potential loophole while working with Django Rest Framework is the default permissions that you setup from the settings of your application; if for example you AllowAny in the settings it'll make all the views publicly accessible unless you specifically override the permission classes in each view.