Django Rest Framework Token Authentication
Asked Answered
I

7

90

I have read the Django Rest Framework Guides and done all the tutorials. Everything seemed to make sense and work just how it should. I got basic and session authentication working as described.

django rest framework - api guide

However, I'm struggling with the Token Authentication part of the documentation, it's a little lacking or does not go into as much depth as the tutorials.

django-rest-framework - token authentication

It says I need to create tokens for users but does state where in models.py?

Can someone explain the Token Authentication part of the documentation a little better for a first-timer?

Illaffected answered 12/2, 2013 at 17:20 Comment(0)
C
74

No, not in your models.py -- on the models side of things, all you need to do is include the appropriate app (rest_framework.authtoken) in your INSTALLED_APPS. That will provide a Token model which is foreign-keyed to User.

What you need to do is decide when and how those token objects should be created. In your app, does every user automatically get a token? Or only certain authorized users? Or only when they specifically request one?

If every user should always have a token, there is a snippet of code on the page you linked to that shows you how to set up a signal to create them automatically:

@receiver(post_save, sender=User)
def create_auth_token(sender, instance=None, created=False, **kwargs):
    if created:
        Token.objects.create(user=instance)

(put this in a models.py file, anywhere, and it will be registered when a Django thread starts up)

If tokens should only be created at certain times, then in your view code, you need to create and save the token at the appropriate time:

# View Pseudocode
from rest_framework.authtoken.models import Token

def token_request(request):
    if user_requested_token() and token_request_is_warranted():
        new_token = Token.objects.create(user=request.user)

Once the token is created (and saved), it will be usable for authentication.

Carycaryatid answered 12/2, 2013 at 17:30 Comment(2)
whats the meaning of post_save ?Totally
@244boy It's setting up create_auth_token as a signal handler so that whenever a User is saved (hence post_save), create_auth_token gets invoked. Signals are django's internal lifecycle event handling mechanism.Scrawny
H
95

@ian-clelland has already provided the correct answer. There are just a few tiny pieces that wasn't mentioned in his post, so I am going to document the full procedures (I am using Django 1.8.5 and DRF 3.2.4):

  1. Do the following things BEFORE you create the superuser. Otherwise, the superuser does not get his/her token created.

  2. Go to settings.py and add the following:

    INSTALLED_APPS = (
        'rest_framework',
        'rest_framework.authtoken',
        'myapp',
    )
    
    REST_FRAMEWORK = {
        'DEFAULT_PERMISSION_CLASSES': (
            'rest_framework.permissions.IsAuthenticated',
        ),
        'DEFAULT_AUTHENTICATION_CLASSES': (
            'rest_framework.authentication.TokenAuthentication',
        )
    }
    
  3. Add the following code in myapp's models.py:

    from django.db.models.signals import post_save
    from django.dispatch import receiver
    from rest_framework.authtoken.models import Token
    from django.conf import settings
    
    # This code is triggered whenever a new user has been created and saved to the database
    @receiver(post_save, sender=settings.AUTH_USER_MODEL)
    def create_auth_token(sender, instance=None, created=False, **kwargs):
        if created:
            Token.objects.create(user=instance)
    

    Alternatively, if you want to be more explicit, create a file named signals.py under myapp project. Put the code above in it, then in __init__.py, write import signals

  4. Open up a console window, navigate to your project dir, and enter the following command:

    python manage.py migrate
    python manage.py makemigrations
    

    Take a look in your database, a table named authtoken_token should be created with the following fields: key (this is the token value), created (the datetime it was created), user_id (a foreign key that references the auth_user table's id column)

  5. create a superuser with python manage.py createsuperuser. Now, take a look at the authtoken_token table in your DB with select * from authtoken_token;, you should see a new entry has been added.

  6. Using curl or a much simpler alternative httpie to test access to your api, I am using httpie:

    http GET 127.0.0.1:8000/whatever 'Authorization: Token your_token_value'
    

    That's it. From now on, for any API access, you need to include the following value in the HTTP header (pay attention to the whitespaces):

    Authorization: Token your_token_value
    
  7. (Optional) DRF also provides the ability to return a user's token if you supply the username and password. All you have to do is to include the following in urls.py:

    from rest_framework.authtoken import views
    
    urlpatterns = [
        ...
        url(r'^api-token-auth/', views.obtain_auth_token),
    ]
    

    Using httpie to verify:

    http POST 127.0.0.1:8000/api-token-auth/ username='admin' password='whatever'
    

    In the return body, you should see this:

    {
        "token": "blah_blah_blah"
    }
    

That's it!

Helfand answered 27/10, 2015 at 3:13 Comment(8)
Thanks for the detailed comment. where does the token get matched ? Can we edit anything ?Barrybarrymore
@rrmo The tokens are stored in a database table named auth_token (or something similar, I cannot remember the exact name. The table only has three columns, primary key, token, and a foreign key to the user model). Every time an authentication request is received, I think the database table is fetched to compare the incoming token with the stored ones.Helfand
@Helfand Regarding Point#3: Putting code in signals.py and adding import signals in __init__.py raises django.core.exceptions.AppRegistryNotReady: Apps aren't loaded yet in Django 1.9.Florez
Bu how do you receive the token, for example from a mobile app, you generate the token using username and password (For example create a base64 token) and send it in the request?Abdulabdulla
@JesusAlmaral The token is created on the server side not client side. After the user fill out registration information and send it to the server to create an account, a token is created together with the account. Once the token has been created, you can send its value to the client side.Helfand
Wow thanks Chen!, I asked you another question on your blog (cheng.logdown.com/posts/2015/10/27/…) because I don´t know if it´s right to be asking here hehe, I hope you could help me a little more pleaseAbdulabdulla
@JesusAlmaral check out this post: #33475834Helfand
Thanks for detailed information ! This worked for me.Ringside
C
74

No, not in your models.py -- on the models side of things, all you need to do is include the appropriate app (rest_framework.authtoken) in your INSTALLED_APPS. That will provide a Token model which is foreign-keyed to User.

What you need to do is decide when and how those token objects should be created. In your app, does every user automatically get a token? Or only certain authorized users? Or only when they specifically request one?

If every user should always have a token, there is a snippet of code on the page you linked to that shows you how to set up a signal to create them automatically:

@receiver(post_save, sender=User)
def create_auth_token(sender, instance=None, created=False, **kwargs):
    if created:
        Token.objects.create(user=instance)

(put this in a models.py file, anywhere, and it will be registered when a Django thread starts up)

If tokens should only be created at certain times, then in your view code, you need to create and save the token at the appropriate time:

# View Pseudocode
from rest_framework.authtoken.models import Token

def token_request(request):
    if user_requested_token() and token_request_is_warranted():
        new_token = Token.objects.create(user=request.user)

Once the token is created (and saved), it will be usable for authentication.

Carycaryatid answered 12/2, 2013 at 17:30 Comment(2)
whats the meaning of post_save ?Totally
@244boy It's setting up create_auth_token as a signal handler so that whenever a User is saved (hence post_save), create_auth_token gets invoked. Signals are django's internal lifecycle event handling mechanism.Scrawny
S
20

On Django 1.8.2 and rest framework 3.3.2 following all of the above was not enough to enable token based authentication.

Although REST_FRAMEWORK setting is specified in django settings file, function based views required @api_view decorator:

from rest_framework.decorators import api_view

@api_view(['POST','GET'])
def my_view(request):
    if request.user.is_authenticated():
       ...

Otherwise no token authentication is performed at all

Swear answered 24/1, 2016 at 0:12 Comment(2)
Despite the few upvotes, this answer adds a very useful point: without the @api_view decorator, the views won't use the token auth. Maybe it could be added to the chosen answer.Elinaelinor
Two and a half years later ... THANK YOUMolybdate
A
16

Just to add my two cents to this, if you've got a custom user manager that handles user creation (and activation), you may also perform this task like so:

from rest_framework.authtoken.models import Token
# Other imports

class UserManager(BaseUserManager):

    def create_user(self, **kwargs):
        """
        This is your custom method for creating user instances. 
        IMHO, if you're going to do this, you might as well use a signal.

        """
        # user = self.model(**kwargs) ...
        Token.objects.create(user=user)

    #You may also choose to handle this upon user activation. 
    #Again, a signal works as well here.

    def activate_user(**kwargs):
        # user = ...
        Token.objects.create(user=user)

If you already have users created, then you may drop down into the python shell in your terminal and create Tokens for all the users in your db.

>>> from django.contrib.auth.models import User
>>> from rest_framework.authtoken.models import Token 
>>> for user in User.objects.all():
>>> ...    Token.objects.create(user=user)

Hope that helps.

Astatic answered 21/1, 2014 at 1:32 Comment(0)
M
10

There is a cleaner way to get the user token.

simply run manage.py shell

and then

from rest_framework.authtoken.models import Token
from django.contrib.auth.models import User
u = User.objects.get(username='admin')
token = Token.objects.create(user=u)
print token.key

then a record should be found in table DB_Schema.authtoken_token

Mccarthyism answered 2/3, 2016 at 5:53 Comment(0)
D
7

In addition to the excellent answers here, I'd like to mention a better approach to token authentication: JSON Web Token Authentication. The implementation offered by http://getblimp.github.io/django-rest-framework-jwt/ is very easy to use.

The benefits are explained in more detail in this answer.

Daiquiri answered 10/9, 2016 at 4:38 Comment(0)
S
1

JSON Web Token Authentication is a better alternative than Token Authentication. This project has implemented JWT Auth with Django (http://getblimp.github.io/django-rest-framework-jwt/) but currently the project is unmaintained.

For alternatives you can follow : https://github.com/davesque/django-rest-framework-simplejwt

Saraisaraiya answered 19/9, 2019 at 10:22 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.