---
# System prepended metadata

title: Token Authentication - User Login and Get Token
tags: [Django, REST, ' ']

---

# Token Authentication - User Login and Get Token

###### tags: `Django` `REST` ｀Auth` `Token`

# 零、參考文件

[How to Implement Token Authentication using Django REST Framework](https://simpleisbetterthancomplex.com/tutorial/2018/11/22/how-to-implement-token-authentication-using-django-rest-framework.html)

### Further read: 

[Token Based Authentication for Django Rest Framework](https://medium.com/quick-code/token-based-authentication-for-django-rest-framework-44586a9a56fb)
[ShubhamBansal1997/token-authentication-django](https://github.com/ShubhamBansal1997/token-authentication-django)

[Django Rest Framework Authentication Tutorial](https://wsvincent.com/django-rest-framework-authentication-tutorial/)

[How to Implement Token Authentication with Django REST Framework](https://chrisbartos.com/articles/how-to-implement-token-authentication-with-django-rest-framework/)

# Introduction

In this tutorial you are going to learn how to implement Token-based authentication 
using Django REST Framework (DRF). 
The token authentication works by exchanging username and password for a token 
that will be used in all subsequent requests 
so to identify the user on the server side.

The specifics of how the authentication is handled on the client side vary _a lot_ 
depending on the technology/language/framework you are working with. 
The client could be a mobile application using iOS or Android. 
It could be a desktop application using Python or C++. 
It could be a Web application using PHP or Ruby.

But once you understand the overall process, 
it’s easier to find the necessary resources and documentation for your specific use case.

_Token authentication_ is suitable for _client-server_ applications, 
where the token is _safely stored_. _You should never expose your token_, 
as it would be (sort of) equivalent of a handing out your username and password.

# Implementation

## Simple Api

Let’s create our first API view just to test things out:

``myapi/core/views.py``
```
from rest_framework.views import APIView
from rest_framework.response import Response

class HelloView(APIView):
    def get(self, request):
        content = {'message': 'Hello, World!'}
        return Response(content)
```

Now register a path in the ``urls.py`` module:

``myapi/urls.py``
```
from django.urls import path
from myapi.core import views

urlpatterns = [
    path('hello/', views.HelloView.as_view(), name='hello'),
]
```

So now we have an API with just one endpoint ``/hello/`` 
that we can perform ``GET`` requests. 
We can use the browser to consume this endpoint, 
just by accessing the URL ``http://127.0.0.1:8000/hello/``:

We can also ask to receive the response as plain JSON data 
by passing the ``format`` parameter in the querystring like 
``http://127.0.0.1:8000/hello/?format=json``:

Both methods are fine to try out a DRF API, 
but sometimes a command line tool is more handy as 
we can play more easily with the requests headers. 
You can use _cURL_, which is widely available on all major Linux/macOS distributions:
```
curl http://127.0.0.1:8000/hello/
```

But usually I prefer to use _HTTPie_, which is a pretty awesome Python command line tool:
```
http http://127.0.0.1:8000/hello/
```


Now let’s protect this API endpoint so we can implement the token authentication:

``myapi/core/views.py``
```
from rest_framework.views import APIView
from rest_framework.response import Response
from rest_framework.permissions import IsAuthenticated  # <-- Here

class HelloView(APIView):
    permission_classes = (IsAuthenticated,)             # <-- And here

    def get(self, request):
        content = {'message': 'Hello, World!'}
        return Response(content)
```

Try again to access the API endpoint:
```
http http://127.0.0.1:8000/hello/
```

And now we get an HTTP 403 Forbidden error. 
Now let’s implement the token authentication so we can access this endpoint.

# Implementing the Token Authentication

We need to add _two pieces of information_ in our ``settings.py`` module. 
First include ``rest_framework.authtoken`` to your INSTALLED_APPS and 
include the TokenAuthentication to REST_FRAMEWORK:

> ``settings.py``中
- ``INSTALLED_APPS ＝ []``中加入 ``rest_framework.authtoken``  
- ``REST_FRAMEWORK = []中加入 TokenAuthentication``
並執行``python manage.py migrate``


``myapi/settings.py``
```
INSTALLED_APPS = [
    # Django Apps
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',

    # Third-Party Apps
    'rest_framework',
    'rest_framework.authtoken',  # <-- Here

    # Local Apps (Your project's apps)
    'myapi.core',
]

REST_FRAMEWORK = {
    'DEFAULT_AUTHENTICATION_CLASSES': [
        'rest_framework.authentication.TokenAuthentication',  # <-- And here
    ],
}
```

Migrate the database to create the table that will store the authentication tokens:
```
python manage.py migrate
```

Now we need a user account. 
Let’s just create one using the ``manage.py`` command line utility:
```
python manage.py createsuperuser --username vitor --email vitor@example.com
```

The easiest way to generate a token, just for testing purpose, is using the command line utility again:
```
python manage.py drf_create_token vitor
```

> 使用 command line 創建 user token

This piece of information, 
the random string ``9054f7aa9305e012b3c2300408c3dfdf390fcddf`` 
is what we are going to use next to authenticate.

But now that we have the ``TokenAuthentication`` in place, 
let’s try to make another request to our ``/hello/`` endpoint:

```
http http://127.0.0.1:8000/hello/
```

Notice how our API is now providing some extra information to the client 
on the required authentication method.

So finally, let’s use our token!

http http://127.0.0.1:8000/hello/ 'Authorization: Token 9054f7aa9305e012b3c2300408c3dfdf390fcddf'


Or if it was a Python requests call:
```
import requests

url = 'http://127.0.0.1:8000/hello/'
headers = {'Authorization': 'Token 9054f7aa9305e012b3c2300408c3dfdf390fcddf'}
r = requests.get(url, headers=headers)
```

# User Requesting a Token

The DRF provide an endpoint for the users to request an authentication token 
using their username and password.

Include the following route to the ``urls.py`` module:

``myapi/urls.py``
```
from django.urls import path
from rest_framework.authtoken.views import obtain_auth_token  # <-- Here
from myapi.core import views

urlpatterns = [
    path('hello/', views.HelloView.as_view(), name='hello'),
    path('api-token-auth/', obtain_auth_token, name='api_token_auth'),  # <-- And here
]
```

So now we have a brand new API endpoint, 
which is ``/api-token-auth/``. Let’s first inspect it:
```
http http://127.0.0.1:8000/api-token-auth/
```

It doesn’t handle ``GET`` requests. 
Basically it’s just a view to receive a ``POST`` request with ``username`` and ``password``.

Let’s try again:

The response body is the token associated with this particular user. 
After this point you store this token and apply it to the future requests.

Then, again, the way you are going to make the ``POST`` request to the API 
depends on the language/framework you are using.

If this was an Angular_ client, you could store the token in the ``localStorage``, 
if this was a Desktop CLI application 
you could store in a text file in the user’s home directory in a _dot file_.

# Conclusions

Hopefully this tutorial provided some insights on how the token authentication works. 
I will try to follow up this tutorial 
providing some concrete examples of Angular applications, 
command line applications and Web clients as well.

It is important to note that _the default Token implementation has some limitations_ 
such as _only one token per user_, _no built-in way to set an expiry date to the token_.

> 一個 User 對應一個 token; token的過期時間要另外管理！

You can grab the code used in this tutorial at [github.com/sibtc/drf-token-auth-example](https://github.com/sibtc/drf-token-auth-example).