1
votes

I'm new to Python and Django REST Framework and I'm trying to configure authentication using JWT (https://jpadilla.github.io/django-rest-framework-jwt/). I'm able to create a token for a user upon registration however I'm getting an "Invalid Signature" error when I try to authenticate through my api. I have confirmed the error at https://jwt.io/. This seems to mean my token is being created improperly. Any Ideas?

This is my configuration:

from django.db import models

class User(models.Model):
    first_name = models.CharField(max_length=45)
    last_name = models.CharField(max_length=45)
    username = models.CharField(max_length=45, unique=True)
    phone = models.CharField(max_length=20)
    password = models.CharField(max_length=100, blank=False, default='')

from rest_framework import serializers
from . models import User
from django.contrib.auth.hashers import make_password

class UserSerializer(serializers.ModelSerializer):
    class Meta:
        model = User
        fields = ('id', 'first_name', 'last_name', 'username', 'phone', 
'password')
    extra_kwargs = {'password': {'write_only': True}}
    def create(self, validated_data):
        # the create method creates and saves an object in a single statement
        user = User.objects.create(
            first_name = validated_data['first_name'],
            last_name = validated_data['last_name'],
            username = validated_data['username'],
            phone = validated_data['phone'],
            password = make_password(validated_data['password']),
        )

        return user

from joyrides_api.models import User
from joyrides_api.serializers import UserSerializer
from rest_framework.response import Response
from rest_framework.views import APIView
from rest_framework import status
from rest_framework_jwt.utils import jwt_payload_handler
from rest_framework import permissions
from rest_framework_jwt.settings import api_settings
from rest_framework.permissions import AllowAny
from rest_framework_jwt.authentication import JSONWebTokenAuthentication

class UserList(APIView):

    permission_classes = (AllowAny,)
    # this method creates the user
    def post(self, request, format=None):
            serializer = UserSerializer(data=request.data)
            if serializer.is_valid():
                # the save method calls serializer's create method
                user = serializer.save()
                if user:
                    jwt_payload_handler = api_settings.JWT_PAYLOAD_HANDLER
                    jwt_encode_handler = api_settings.JWT_ENCODE_HANDLER
                    payload = jwt_payload_handler(user)
                    token = jwt_encode_handler(payload)
                    json = serializer.data
                    json['token'] = token
                    return Response(json, status=status.HTTP_201_CREATED)

            return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
3

3 Answers

3
votes

you need to specify authentication_classes as well. Let it be empty and it should work.

0
votes

The issue for me was when I created my users using the django.db.model create method:

from . models import User

def create(self, validated_data):
        user = User.objects.create(
            first_name = validated_data['first_name'],
            ...
        )

        return user

I wasn't also creating a user in the Django user model at django.contrib.auth.models which is the model Django and the JWT framework use for authentication. This isn't all that straightforward for a beginner and I'm kind of surprised this isn't a bigger issue considering the popularity of JWT with Django (or so it seemed). I suppose anyone would tell me I should have spent more time in the docs.

I digress, the elegant fix is to customize your user model by extending django.contribut.auth.models' AbstractUser which (I believe) links the pertinent parts of your user model to Django's model. Instructions here: https://docs.djangoproject.com/en/1.11/topics/auth/customizing/

The option I did to get this up and running (although I plan on switching to a custom model soon) is to save your user object to the Django user model using django.contrib.auth.models' create_user method which operates identical to the create method above except it saves to Django's user model.

0
votes

I found that the 'Invalid Signature' error comes up when I create a custom User model. I resolved this by:

  1. Instantiating a model based on Django's User model:

``

from django.db import models
from django.contrib.auth.models import AbstractUser

class User(AbstractUser):
    .....

``

  1. In settings.py, use AUTH_USER_MODEL to point to the custom user model.

``

AUTH_USER_MODEL = 'user.User'

``

where 'user.User' points to User model in user app.

Proceed with token generation. The token will validate now.