<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Jefferson Oliveira</title>
    <description>The latest articles on DEV Community by Jefferson Oliveira (@jefferson).</description>
    <link>https://dev.to/jefferson</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F693988%2F28bdd677-6478-44f6-9d6d-20ee21607b39.jpeg</url>
      <title>DEV Community: Jefferson Oliveira</title>
      <link>https://dev.to/jefferson</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/jefferson"/>
    <language>en</language>
    <item>
      <title>Token Based User Authentication With Django</title>
      <dc:creator>Jefferson Oliveira</dc:creator>
      <pubDate>Mon, 20 Sep 2021 16:08:32 +0000</pubDate>
      <link>https://dev.to/jefferson/token-based-user-authentication-with-django-i1f</link>
      <guid>https://dev.to/jefferson/token-based-user-authentication-with-django-i1f</guid>
      <description>&lt;h2&gt;
  
  
  INTRODUCTION
&lt;/h2&gt;

&lt;p&gt;When creating a REST API for client applications to communicate with, it is common to want it to have some authentication and permissions. In this post I would like to walk through the set up of the API for a Books collection application. The API allows users to be created, to get access token and to use it on future requests. This way unauthenticated users can see the list of books, but only authenticated users can create, edit or delete books.&lt;/p&gt;

&lt;p&gt;For this we'll be using the &lt;a href="https://www.djangoproject.com/" rel="noopener noreferrer"&gt;Django Framework&lt;/a&gt;, with the &lt;a href="https://www.django-rest-framework.org/" rel="noopener noreferrer"&gt;Django REST Framework&lt;/a&gt;. If you still don't know them go ahead and check their website, they have great tutorials to get you started.&lt;/p&gt;

&lt;p&gt;For making requests to test it, I find &lt;a href="https://insomnia.rest/" rel="noopener noreferrer"&gt;Insomnia&lt;/a&gt; really good, and hey they have a free tier 😎. Another client that I find really useful is the command line app &lt;a href="https://httpie.io/" rel="noopener noreferrer"&gt;HTTPie&lt;/a&gt;. I'll be using HTTPie for this tutorial, it makes it easier for you to try the commands on your own, and for diplaying the results in text instead of screenshots.&lt;/p&gt;

&lt;p&gt;Finally I saved the result on &lt;a href="https://github.com/jefferson2z/django-token-auth-tutorial" rel="noopener noreferrer"&gt;Github&lt;/a&gt;, in case you get lost or just want to check the final result.&lt;/p&gt;

&lt;p&gt;Withour further ado let's get to it.&lt;/p&gt;

&lt;h2&gt;
  
  
  CREATING THE PROJECT
&lt;/h2&gt;

&lt;p&gt;For this project I will be using pipenv for package management, because it automatically creates and manages the virtual environment. In case you don't have it installed yet, it's quite easy to do it, you can follow the instructions from their &lt;a href="https://pipenv.pypa.io/en/latest/#install-pipenv-today" rel="noopener noreferrer"&gt;documentation&lt;/a&gt;. You can also use &lt;a href="https://docs.python.org/3/tutorial/venv.html" rel="noopener noreferrer"&gt;venv&lt;/a&gt;, &lt;a href="https://python-poetry.org/" rel="noopener noreferrer"&gt;poetry&lt;/a&gt;, or any other tool you prefer.&lt;/p&gt;

&lt;p&gt;Let's start by installing Django, and Django REST framework. Inside the folder you would like to create the project, run the command:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# Install the packages, and creates a virtual environment
pipenv install django djangorestframework

# Activates the virtual environment 
pipenv shell
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now we can create the project for our API.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;django-admin startproject api . 
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;I add the &lt;code&gt;.&lt;/code&gt; character at the end to start the project in the current folder. This way I have the &lt;code&gt;manage.py&lt;/code&gt; file in the same folder as &lt;code&gt;Pipfile&lt;/code&gt;, and just one folder. So our folder structure should look like this&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;.
├── api
│   ├── asgi.py
│   ├── __init__.py
│   ├── settings.py
│   ├── urls.py
│   └── wsgi.py
├── manage.py
├── Pipfile
└── Pipfile.lock
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If instead we hadn't used the &lt;code&gt;.&lt;/code&gt;, we would have the following structure.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;.
├── api
│   ├── api
│   │   ├── asgi.py
│   │   ├── __init__.py
│   │   ├── settings.py
│   │   ├── urls.py
│   │   └── wsgi.py
│   └── manage.py
├── Pipfile
└── Pipfile.lock
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;To tell our project that we are using the REST framework. Add it to &lt;code&gt;INTALLED_APPS&lt;/code&gt; on &lt;code&gt;api/settings.py&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;INSTALLED_APPS = [
    'rest_framework',
    ...
]
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Great, now that we have it installed we can create the database.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;python manage.py migrate
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This creates the database using the default &lt;a href="https://www.sqlite.org/index.html" rel="noopener noreferrer"&gt;SQL Lite&lt;/a&gt;, that is fine for this tutorial. In production however we would probably want to use a different database.&lt;/p&gt;

&lt;h2&gt;
  
  
  CREATING THE BOOKS APP
&lt;/h2&gt;

&lt;p&gt;Now let's create our books app.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;python manage.py startapp books
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;To tell our project that we are using the newly created app, add it to &lt;code&gt;INSTALLED_APPS&lt;/code&gt; on &lt;code&gt;api/settings.py&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;INSTALLED_APPS = [
    'books.apps.BooksConfig',
    ...
]
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We'll create a simple model for books, since this isn't the focus of this tutorial. Edit the &lt;code&gt;books/models.py&lt;/code&gt; file so it looks like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;from django.db import models


class Book(models.Model):
    title = models.CharField(max_length=200)
    description = models.TextField(blank=True

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now we can create the migration and sync the database.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# Create migrations for Books app
python manage.py makemigrations books

# Sync the database 
python manage.py migrate
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;Every time we add a new app to &lt;code&gt;INSTALLED_APPS&lt;/code&gt; or change a model, we can tell Django to create the migrations, with the &lt;code&gt;makemigrations&lt;/code&gt; command. When we're ready we can sync it with the &lt;code&gt;migrate&lt;/code&gt; command.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Create the file &lt;code&gt;books/serializers.py&lt;/code&gt; with the serializer for the Book model.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;from rest_framework import serializers
from books.models import Book

class BookSerializer(serializers.ModelSerializer):
    class Meta:
        model = Book
        fields = ["id", "title", "description"]
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And a view for creating new books and listing the existing ones. On &lt;code&gt;books/views.py&lt;/code&gt; add the following.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;from rest_framework import generics

from books.models import Book
from books.serializers import BookSerializer


class BookList(generics.ListCreateAPIView):
    queryset = Book.objects.all()
    serializer_class = BookSerializer
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And connect the view to our books urls. Create the file &lt;code&gt;books/urls.py&lt;/code&gt; and connect the view to the root of the route.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;from django.urls import path
from books.views import BookList

urlpatterns = [
    path("", BookList.as_view(), name="index"),
]

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And send the routes starting with &lt;code&gt;books&lt;/code&gt; to the Book app, by adding it to  &lt;code&gt;api/urls.py&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;from django.urls import include, path

urlpatterns = [
    ...,
    path("books/", include("books.urls")),
]

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now we can start the server to test the api.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;python manage.py runserver 
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;After running the system check it should start the development server.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Performing system checks...

System check identified no issues (0 silenced).
August 25, 2021 - 22:47:34
Django version 3.2.6, using settings 'api.settings'
Starting development server at http://127.0.0.1:8000/
Quit the server with CONTROL-C.

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now if we send a &lt;code&gt;POST&lt;/code&gt; request to &lt;code&gt;http://127.0.0.1:8000/books/&lt;/code&gt;, with the book title and description.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;http http://127.0.0.1:8000/books/ title='Cool book' description='Long description'

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We'll have created the first book. And it gives the following response:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;HTTP/1.1 201 Created
...

{
    "description": "Long description",
    "id": 1,
    "title": "Cool book"
}

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Go ahead and try creating more books.&lt;/p&gt;

&lt;p&gt;If we send a &lt;code&gt;GET&lt;/code&gt; request to &lt;code&gt;http http://127.0.0.1:8000/books/&lt;/code&gt; we get a list of existing books.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;http http://127.0.0.1:8000/books/
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;It should display a response similar to the following.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;HTTP/1.1 200 OK
...

[
    {
        "description": "Long description",
        "id": 1,
        "title": "Cool book"
    },
    {
        "description": "Long description of another book",
        "id": 2,
        "title": "Fantasy book title"
    }
]

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If we open the route &lt;code&gt;http://127.0.0.1:8000/books&lt;/code&gt; in our browser we should see the following screen, where it lists all the books saved in our database, and we can use the &lt;code&gt;POST&lt;/code&gt; method to add more books.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn.hashnode.com%2Fres%2Fhashnode%2Fimage%2Fupload%2Fv1629932080142%2F-zz7XwgTo.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn.hashnode.com%2Fres%2Fhashnode%2Fimage%2Fupload%2Fv1629932080142%2F-zz7XwgTo.png" alt="Screenshot from 2021-08-25 19-53-58.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Go ahead and try it as well for adding some more books.&lt;/p&gt;

&lt;p&gt;As you will notice, we can see all books, and add books without authentication.&lt;/p&gt;

&lt;p&gt;Let's now change this behaviour, so that anyone can see the list of books, but only registered users can add new books.&lt;/p&gt;

&lt;h2&gt;
  
  
  CREATE USERS
&lt;/h2&gt;

&lt;p&gt;Let's start by creating a separated app for handling our users. On the folder with the &lt;code&gt;manage.py&lt;/code&gt;file run the command&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;python manage.py startapp users
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;install the users app to &lt;code&gt;api/settings.py&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;INSTALLED_APPS = [
    'users.apps.UsersConfig',
        ...
]
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now for our user serializer we have something more interesting. Create the file&lt;br&gt;
&lt;code&gt;users/serializer.py&lt;/code&gt; and add the users serializer:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;from rest_framework import serializers
from django.contrib.auth.models import User


class UserSerializer(serializers.ModelSerializer):
    class Meta:
        model = User
        fields = ["username", "email", "password"]
        extra_kwargs = {"password": {"write_only": True}}

    def create(self, validated_data):
        user = User(email=validated_data["email"], username=validated_data["username"])
        user.set_password(validated_data["password"])
        user.save()
        return user

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;When creating a new user, we use the &lt;code&gt;set_password&lt;/code&gt; method so that we store the password hash instead of the actual password on the database, for security reasons. We set the password field to write_only, this way we can send a password when creating the user, but when we fetch the users list, it is not returned.&lt;/p&gt;

&lt;p&gt;Similar to our books view create the user view on the file &lt;code&gt;users/views.py&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;from django.contrib.auth.models import User
from users.serializers import UserSerializer
from rest_framework import generics


class UserCreate(generics.ListCreateAPIView):
    queryset = User.objects.all()
    serializer_class = UserSerializer
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;and create the urls for users on &lt;code&gt;users/urls.py&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;from django.urls import path
from users import views

urlpatterns = [
    path('', views.UserCreate.as_view()),
]
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Connect the app to &lt;code&gt;users&lt;/code&gt; routes on &lt;code&gt;api/urls.py&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;urlpatterns = [
        ...,
    path("users/", include("users.urls")),
]
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now we can start the server again and create new users:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;http http://127.0.0.1:8000/users/ username='Luke' email='luke@cool.com' password='lukespassword'
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And we should get the following response.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;HTTP/1.1 201 Created
...

{
    "email": "luke@cool.com",
    "username": "Luke"
}

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;When we send a &lt;code&gt;GET&lt;/code&gt; request we'll get a list of all users.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;http http://127.0.0.1:8000/users/

HTTP/1.1 200 OK
...

[
    {
        "email": "luke@cool.com",
        "username": "Luke"
    },
    {
        "email": "leia@cool.com",
        "username": "Leia"
    }
]

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Notice that we can get the list of users, but the password is not returned.&lt;/p&gt;

&lt;h2&gt;
  
  
  USERS TOKEN
&lt;/h2&gt;

&lt;p&gt;Right now we are able to create users, but they have no way to authenticate to our API. For that we will create a route where the user can provide his credentials and get a token which can be used when sending further requests.&lt;/p&gt;

&lt;p&gt;To do this, first add the &lt;code&gt;rest_framework.authtoken&lt;/code&gt; to our installed apps on &lt;code&gt;api/settings.py&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;INSTALLED_APPS = [
    'rest_framework.authtoken',
        ...,
]
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;To create the database tables for the tokens run the command:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;python manage.py migrate
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Django REST Framework already provides us with the view &lt;code&gt;obtain_auth_token&lt;/code&gt; for handling user authentication. All we need is to connect it into a route path. Into &lt;code&gt;users/urls.py&lt;/code&gt; add the import and plug the view.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;from rest_framework.authtoken.views import obtain_auth_token


urlpatterns = [
...,
    path('login/', obtain_auth_token)
]


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now we can start the server and test it.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;http http://127.0.0.1:8000/users/login/ username='Luke' password='lukespassword'

HTTP/1.1 200 OK
...

{
    "token": "6650c889f12dafb1cff9dd50b58254f47df67288"
}


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Go ahead and try sending a wrong combination of username and password to see it denying, as expected. &lt;/p&gt;

&lt;p&gt;Now we can send this token in the &lt;code&gt;Authorization&lt;/code&gt; HTTP header in our future requests in the format bellow, this way the API can provide us with the correct permissions. For instance, for the token above, the header would be:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Authorization: Token 6650c889f12dafb1cff9dd50b58254f47df67288
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Notice the space between the word &lt;code&gt;Token&lt;/code&gt; and the token itself.&lt;/p&gt;

&lt;h2&gt;
  
  
  PROTECT ROUTES WITH TOKEN
&lt;/h2&gt;

&lt;p&gt;The last step is for us to protect our views with the proper permissions. We want to allow any user to see the list of books, but only authenticated users to be able to create new books.&lt;/p&gt;

&lt;p&gt;In &lt;code&gt;books/views.py&lt;/code&gt;, set &lt;code&gt;permission_classes&lt;/code&gt; to tell it the type of permission we want. Also set &lt;code&gt;authentication_classes&lt;/code&gt; to the authentication method being used.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;from rest_framework.authentication import TokenAuthentication
from rest_framework.permissions import IsAuthenticatedOrReadOnly


class BookList(generics.ListCreateAPIView):
    queryset = Book.objects.all()
    serializer_class = BookSerializer
    permission_classes = [IsAuthenticatedOrReadOnly]
    authentication_classes = [TokenAuthentication]
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now if we try creating a new book with an unauthorized user it denies it.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;http http://127.0.0.1:8000/books/ title='Sad book' description="I won't work"


HTTP/1.1 401 Unauthorized
...

{
    "detail": "Authentication credentials were not provided."
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If you substitute the &lt;code&gt;X&lt;/code&gt; bellow with the token returned for your user, it works!&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;http http://127.0.0.1:8000/books/ title='Happy book' description="I work" Authorization:"Token XXXXXXXXXXXXXXXXX"


HTTP/1.1 201 Created
...

{
    "description": "I work",
    "id": 3,
    "title": "Happy book"
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And that's it! 🎉🎉🎉&lt;/p&gt;

&lt;h2&gt;
  
  
  CONCLUSION
&lt;/h2&gt;

&lt;p&gt;Having it working I would encourage you to check out the following documentations to learn more about the topic and making it more robust:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://docs.djangoproject.com/en/3.2/topics/auth/" rel="noopener noreferrer"&gt;Django User Authentication documentation&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://www.django-rest-framework.org/api-guide/authentication/" rel="noopener noreferrer"&gt;Rest Framework Authentication documentation&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://www.django-rest-framework.org/api-guide/permissions/" rel="noopener noreferrer"&gt;Rest Framework Permissions documentation&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;I hope you enjoyed it and that this content might be useful to someone. It was my first blog post but I tried writing about a subject the I struggled with. I greatly appreciate comments, feedback and suggestions for other topics you would like me to write about.&lt;/p&gt;

</description>
      <category>python</category>
      <category>django</category>
      <category>webdev</category>
      <category>api</category>
    </item>
  </channel>
</rss>
