# 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).