Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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

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 ?
like image 432
diwakarb Avatar asked Jun 30 '15 20:06

diwakarb


People also ask

How JWT token works in Django REST Framework?

After verifying the credentials, the server issues two JSON Web Tokens to the user. One of them is an Access Token and the other is a Refresh Token. The frontend of your application then stores the tokens securely and sends the Access Token in the Authorization header of all requests it then sends to the server.

How do you get auth tokens in Django?

Request an Auth Token in Django REST FrameworkThe Django REST Framework will provide an endpoint so that the user can request a Token for authentication with their password and username. It won't handle GET requests. It will inform you to use POST request with username and password.


2 Answers

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.

like image 137
James Muranga Avatar answered Oct 05 '22 23:10

James Muranga


The Accepted answer has some code that generates token but it doesn't show how to integrate it in serializer/view. Also not sure that manual jwt.encode is a good modern way of doing this if we already have jwt_encode_handler to do this. You can create SerializerMethodField and create tokens there:

token = serializers.SerializerMethodField()

def get_token(self, obj):
    jwt_payload_handler = api_settings.JWT_PAYLOAD_HANDLER
    jwt_encode_handler = api_settings.JWT_ENCODE_HANDLER

    payload = jwt_payload_handler(obj)
    token = jwt_encode_handler(payload)
    return token

Then add token field to Meta.fields.

Working Example

like image 34
Ivan Borshchov Avatar answered Oct 06 '22 00:10

Ivan Borshchov