I'm replying to this for future reference.
I hope it helps someone.
There are a number of issues in your code that are causing that error.
1:You're using authenticate
and login
but haven't imported them.
from rest_framework import status
from rest_framework.views import APIView
from rest_framework.response import Response
from rest_framework.permissions import AllowAny
from django.contrib.auth import authenticate
from rest_framework.authtoken.models import Token
from django.contrib.auth import get_user_model
from .serializers import AccountSerializer
from .models import Account
User = get_user_model()
class AuthRegister(APIView):
"""
Register a new user.
"""
serializer_class = AccountSerializer
permission_classes = (AllowAny,)
def post(self, request, format=None):
serializer = self.serializer_class(data=request.data)
if serializer.is_valid():
user = serializer.save()
# Create token for the new user
token, created = Token.objects.get_or_create(user=user)
return Response({
'user': serializer.data,
'token': token.key
}, status=status.HTTP_201_CREATED)
return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
class AuthLogin(APIView):
"""
Login user and return token
"""
permission_classes = (AllowAny,)
def post(self, request, format=None):
data = request.data
email = data.get('email', None)
password = data.get('password', None)
if email is None or password is None:
return Response({
'error': 'Please provide both email and password.'
}, status=status.HTTP_400_BAD_REQUEST)
# If using custom user model, you might need to get user first
try:
user = Account.objects.get(email=email)
if user.check_password(password):
token, created = Token.objects.get_or_create(user=user)
return Response({
'token': token.key,
'user_id': user.id,
'email': user.email
}, status=status.HTTP_200_OK)
else:
return Response({
'error': 'Invalid credentials.'
}, status=status.HTTP_401_UNAUTHORIZED)
except Account.DoesNotExist:
return Response({
'error': 'Invalid credentials.'
}, status=status.HTTP_401_UNAUTHORIZED)
2:You're using JWT tokens in URLs but session-based login()
in your view.
from django.urls import path
from .views import AuthRegister, AuthLogin
from rest_framework_simplejwt.views import (
TokenObtainPairView,
TokenRefreshView,
TokenVerifyView,
)
urlpatterns = [
path('register/', AuthRegister.as_view(), name='auth_register'),
path('login/', AuthLogin.as_view(), name='auth_login'),
# JWT endpoints (alternative to your custom login)
path('token/', TokenObtainPairView.as_view(), name='token_obtain_pair'),
path('token/refresh/', TokenRefreshView.as_view(), name='token_refresh'),
path('token/verify/', TokenVerifyView.as_view(), name='token_verify'),
]
3:Your AuthLogin
view doesn't generate or return tokens.
# serializers.py
from rest_framework import serializers
from .models import Account
class AccountSerializer(serializers.ModelSerializer):
password = serializers.CharField(write_only=True)
class Meta:
model = Account
fields = ('id', 'email', 'password', 'first_name', 'last_name') # adjust fields as needed
extra_kwargs = {'password': {'write_only': True}}
def create(self, validated_data):
password = validated_data.pop('password')
user = Account.objects.create(**validated_data)
user.set_password(password)
user.save()
return user
4:If you're using a custom Account
model, Django's default authenticate()
might not work properly.
INSTALLED_APPS = [
'rest_framework',
'rest_framework.authtoken',
'rest_framework_simplejwt',
]
REST_FRAMEWORK = {
'DEFAULT_AUTHENTICATION_CLASSES': [
'rest_framework.authentication.TokenAuthentication',,
],
}
5:django-rest-framework-jwt
is deprecated. Use djangorestframework-simplejwt
instead.
First, install the correct JWT package:
pip uninstall djangorestframework-jwt
pip install djangorestframework-simplejwt
# Even simpler approach using DRF generics
from rest_framework import generics
from rest_framework.authtoken.views import ObtainAuthToken
from rest_framework.authtoken.models import Token
from rest_framework.response import Response
class CustomAuthToken(ObtainAuthToken):
def post(self, request, *args, **kwargs):
serializer = self.serializer_class(data=request.data,
context={'request': request})
serializer.is_valid(raise_exception=True)
user = serializer.validated_data['user']
token, created = Token.objects.get_or_create(user=user)
return Response({
'token': token.key,
'user_id': user.pk,
'email': user.email
})
class AuthRegister(generics.CreateAPIView):
serializer_class = AccountSerializer
permission_classes = (AllowAny,)
I hope this sorts the issue.