Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Multiple Token Authentication in Django Rest Framework

How can a user login in multiple devices because what we have is just a single Token Authentication on our django app. As an authenticated user when I login on Google Chrome it works fine but when I visit at the mozilla time and I logged out at the chrome the token that has been created has been deleted upon logout so when I login at mozilla, the token is already gone and we can not log-in on mozilla and throws a Forbidden response on the console.

like image 395
Dean Christian Armada Avatar asked Mar 07 '16 10:03

Dean Christian Armada


2 Answers

You're question is a little convoluted, but I think you are getting at the problem referenced here: https://github.com/tomchristie/django-rest-framework/issues/601

The official token authentication does not support (and unfortunately has no intention of supporting) multiple tokens, but you may be able to use django-rest-knox, available here: https://github.com/James1345/django-rest-knox

Edit: I previously recommended django-rest-multitoken, but django-rest-knox seems to be more actively maintained.

like image 148
Jonathan Richards Avatar answered Oct 22 '22 01:10

Jonathan Richards


It's been years since this question was asked, I worked around this issue with few lines of code, I hope someone will benefit from this.

DRF authentication relies on two things:

  1. Token model (which is the source of this issue).
  2. Authentication class.

I provided my own implementations of these two, and passed them to DRF.

# models.py

from django.conf import settings
from django.db import models
from rest_framework.authtoken.models import Token

class MultiToken(Token):
user = models.ForeignKey(  # changed from OneToOne to ForeignKey
    settings.AUTH_USER_MODEL, related_name='tokens',
    on_delete=models.CASCADE, verbose_name=_("User")
)

Then I implemented an Authentication class, just to override the model.

# appname.authentication.py
from rest_framework.authentication import TokenAuthentication

from appname.models import MultiToken


class MultiTokenAuthentication(TokenAuthentication):
    model = MultiToken

Pass this Authentication class, to DRF.

REST_FRAMEWORK = {
    'DEFAULT_AUTHENTICATION_CLASSES': [
        'appname.authentication.MultiTokenAuthentication',
    ],
    ...
}

of course, Since I inherited from DRF Token model, I had to remove rest_framework.authtoken from INSTALLED_APPS.

I also, changed the ObtainAuthToken APIView to suit this new change.

class LoginApi(ObtainAuthToken):
    def post(self, request, *args, **kwargs):
        context = dict(request=request, view=self)
        serializer = self.serializer_class(data=request.data, context=context)
        serializer.is_valid(raise_exception=True)
        user = serializer.validated_data['user']
        update_last_login(None, user, )
        token = MultiToken.objects.create(user=user)
        data = {'token': token.key}

        return Response(data)

HOPE THIS HELPS.

like image 27
Simou Avatar answered Oct 22 '22 02:10

Simou