Do not Reinvent the Wheel: Utilize Django’s Built-in Auth App to Create a Robust Authentication System
Tags: django, webdev, beginners, authentication
Published: 2024-05-16 22:45:56

## Introduction
Many web applications implement a user authentication system for purposes of data security. A robust user authentication system protects user data against unauthorized access or loss.  Many server-side programming frameworks like Django provide a ready-made user authentication system. Optionally, a developer can configure such a system from scratch based on project needs. The later is a risky endeavor, as such a system is less secure than a built-in one. Moreover, opting to create from scratch may be an overkill in many scenarios. As best practice, one should use the built-in authentication system which has already been tested and optimized. This article discusses Django’s built-in user authentication system and how you, as a Django developer, can configure it in your project.

## Prerequisites
* An understanding of how to build with Django.

## Django's Auth App
If you peruse [Django’s official docs](https://docs.djangoproject.com/en/3.1/topics/auth/default/#module-django.contrib.auth.views) or the source code available on [Github](https://github.com/django/django), you should locate the **auth** app documentation. The auth app ships with Django, and is installed in your project when you run the `django-admin start project` command.  Let us observe this in real-time by creating a Django project.

First create your project directory and install Django using your preferred Python virtual environment package. Do not forget to activate the virtual environment.
```shell
mkdir code && cd code
pipenv install django
pip shell
```
Next start a Django project to generate manage.py file and other config files.
```shell
django-admin startproject user-auth .
python manage.py migrate
Python manage.py runserver
```
You can visit http://127.0.0.1:8000 to confirm that you have successfully created a Django project.

Now open our settings.py file to confirm that an auth app exists. In your settings.py under `INSTALLED-APPS`, you should see this line
`'django.contrib.auth'`

```python
# user-auth/settings.py
INSTALLED_APPS = [
'django.contrib.admin',
'django.contrib.auth',  # built-in authentication
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
]
```

The built-in authentication system comes with its own URL routes and views. Before you configure the system in your project though, you have to include its URL routes in your project-level urls.py file. This is necessary to enable the use of the provided routes locally.

```python
# user-auth/urls.py
from django.contrib import admin
from django.urls import path, include

urlpatterns = [
    # Django admin
    path('admin/', admin.site.urls),
    # User management
    path('accounts/', include('django.contrib.auth.urls')), # This

                                    ...
]
```
We are prefixing all our user authentication routes with **accounts/** as a convection. You could use any prefix though.

Let's inspect the URL routes that ship with the auth app. You can inspect the[ docs](https://docs.djangoproject.com/en/3.1/topics/auth/default/#module-django.contrib.auth.views) or [Django source code](https://github.com/django/django) for the routes. Auth app provides the following routes:
```python
accounts/login/ [name='login']
accounts/logout/ [name='logout']
accounts/password_change/ [name='password_change']
accounts/password_change/done/ [name='password_change_done']
accounts/password_reset/ [name='password_reset']
accounts/password_reset/done/ [name='password_reset_done']
accounts/reset/<uidb64>/<token>/ [name='password_reset_confirm']
accounts/reset/done/ [name='password_reset_complete']
```

## Implement Login and Logout
Now it's time to configure a simple login and logout. In the routes above, we can see that similar URLs exist.

An important thing to note: The built-in auth app provides the URLs and the views necessary to handle login, logout and other user authentication-related functionality. However, it is up to the Django developer to create templates that render various authentication pages.

We are going to create three pages for rendering purposes: a home page, a login and a logout page

### A Simple Homepage
We are going to create a dedicated pages app to render our homepage
```shell
python manage.py startapp pages
```
Then we configure the URL route for the home page
```python
# config/urls.py

from django.contrib import admin
from django.urls import path, include

urlpatterns = [
    # Django admin
    path('admin/', admin.site.urls),
    # User management
    path('accounts/', include('django.contrib.auth.urls')),
    # Local apps
    path('', include('pages.urls')), # This
]
```
Then create a urls.py file inside the pages app and update it with the home page route
```python
# pages/urls.py
from django.urls import path
from .views import HomePageView

urlpatterns = [
    path('', HomePageView.as_view(), name='home'),
]
```
Next we need to provide a view logic which the home page URL should resolve to, and a template to
render the page(This article assumes you are sufficiently familiar with the flow of building a web page using Django).

```python
# pages/views
from django.views.generic import TemplateView


class HomePageView(TemplateView):
    """Renders the home page"""
    template_name = 'home.html'
```
Now we create a home page template. We need to update our settings.py file to create a route to our templates directory. Also, we need to create a templates directory inside our project-level directory.
```python
# config/settings.py
…
TEMPLATES = [
    {
        'BACKEND': 'django.template.backends.django.DjangoTemplates',
        'DIRS': [str(BASE_DIR.joinpath('templates'))], # update template DIRS like this
        'APP_DIRS': True,
        'OPTIONS': {
            'context_processors': [
                'django.template.context_processors.debug',
                'django.template.context_processors.request',
                'django.contrib.auth.context_processors.auth',
                'django.contrib.messages.context_processors.messages',
            ],
        },
    },
]
…
```
Then create a templates directory:
```shell
mkdir templates
```
Finally create the home page. We want the page to have a login link if a user is logged out, and
a logout link if a user is logged in. We will use conditional rendering.
```html
<!--templates/home.html-->
<!DOCTYPE html>
<html>

  <head>
    <title>home</title>
  </head>

  <body>
    <div>
      <h1>Home page</h1>
      {% if user.is_authenticated %}
      <span>Hello, {{ user.username }}</span>
      <span><a href="{% url 'logout' %}">Log Out</a></span>
      {% else %}
      <a href="{% url 'login' %}">Log In</a>
      {% endif %}
    </div>
  </body>

</html>
```
Note the login and logout links provided in the page. They use similar namespaces provided in the auth/urls.py file. Now visit http://127.0.0.1:8000 to confirm if the home page renders correctly.

However, If you click on the login link, you will encounter a TemplateDoesNotExist Error since we do not yet have a login template.

If you inspect [auth/views.py](https://github.com/django/django/blob/b9cf764be62e77b4777b3a75ec256f6209a57671/django/contrib/auth/views.py) file, the login template provided is located at registration/login.html. It means we need to create a login template under a "registration" directory. You could create it under any directory. However, that would mean overriding the built-in LoginView provided by the auth app, which we do not want. Therefore, a suitable option is to create a similar directory structure within our templates directory
```shell
mkdir templates/registration
touch templates/registration/login.html
```
### Create a simple login
Our login page looks like this:
```html
<!--templates/registration/login.html-->
<!DOCTYPE html>
<html>

    <head>
        <title>Login</title>

    </head>

    <body>
        <div>
            <h2>Log In</h2>
            <form method="post">
                {% csrf_token %}
                {{ form.as_p }}
                <button type="submit">Log In</button>
            </form>
        </div>
    </body>

</html>
```
Try accessing the page from your browser at http://127.0.0.1:8000/accounts/login /. If you click on the Log In button, you will run into a 404 error. That means the page you are requesting does not exist on the server. If you inspect the URL in your address bar, you will see that the login provided by auth redirects to /accounts/profile/ page by default. We have not configured such a page, hence the 404 error.

A simple solution is to change the redirect to point to a page we have already configured, in this case our home page. To implement a redirect to the home page, we need to set the LOGIN_REDIRECT_URL directive explicitly in our settings.py file to point to our home page
```python
# config/settings.py
# Add this at the end
LOGIN_REDIRECT_URL = 'home'
```
### Implement Logout
Auth does not provide a logout template. Only URL and view. We could create a custom logout page which the logout URL should resolve to, but that would be unnecessary. The only thing we need to do is to update the LOGOUT_REDIRECT_URL which should redirect a user to one of our existing pages when they log out:
```python
# config/settings.py
LOGIN_REDIRECT_URL = 'home'
LOGOUT_REDIRECT_URL = 'home' # This
```
Both our login and logout are now redirecting to our home page
### Configure Sign Up
Django does not provide a built-in sign up functionality. The Developer should configure it manually. Manually setting up user registration is beyond the scope of this tutorial.
## Conclusion
Django is a mature and robust web development framework that comes with many pre-built features. This is intentional, as Django purposes to speed up development. Among the features that ship with Django is the auth app, which contains a pre-built user authentication functionality. The auth app avails login, logout and other user-authentication related functionality for easy configuration. You can, and probably should, leverage the built-in login and logout functionality to quickly set up a user authentication system, so that you can focus on other core features of your web app. Happy coding!