DEV Community

Nick
Nick

Posted on

Do not Reinvent the Wheel: Utilize Django’s Built-in Auth App to Create a Robust Authentication System

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 or the source code available on Github, 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.

mkdir code && cd code
pipenv install django
pip shell
Enter fullscreen mode Exit fullscreen mode

Next start a Django project to generate manage.py file and other config files.

django-admin startproject user-auth .
python manage.py migrate
Python manage.py runserver
Enter fullscreen mode Exit fullscreen mode

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'

# 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',
]
Enter fullscreen mode Exit fullscreen mode

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.

# 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

                                    ...
]
Enter fullscreen mode Exit fullscreen mode

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 or Django source code for the routes. Auth app provides the following routes:

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']
Enter fullscreen mode Exit fullscreen mode

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

python manage.py startapp pages
Enter fullscreen mode Exit fullscreen mode

Then we configure the URL route for the home page

# 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
]
Enter fullscreen mode Exit fullscreen mode

Then create a urls.py file inside the pages app and update it with the home page route

# pages/urls.py
from django.urls import path
from .views import HomePageView

urlpatterns = [
    path('', HomePageView.as_view(), name='home'),
]
Enter fullscreen mode Exit fullscreen mode

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

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


class HomePageView(TemplateView):
    """Renders the home page"""
    template_name = 'home.html'
Enter fullscreen mode Exit fullscreen mode

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.

# 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',
            ],
        },
    },
]

Enter fullscreen mode Exit fullscreen mode

Then create a templates directory:

mkdir templates
Enter fullscreen mode Exit fullscreen mode

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.

<!--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>
Enter fullscreen mode Exit fullscreen mode

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 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

mkdir templates/registration
touch templates/registration/login.html
Enter fullscreen mode Exit fullscreen mode

Create a simple login

Our login page looks like this:

<!--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>
Enter fullscreen mode Exit fullscreen mode

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

# config/settings.py
# Add this at the end
LOGIN_REDIRECT_URL = 'home'
Enter fullscreen mode Exit fullscreen mode

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:

# config/settings.py
LOGIN_REDIRECT_URL = 'home'
LOGOUT_REDIRECT_URL = 'home' # This
Enter fullscreen mode Exit fullscreen mode

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!

Top comments (0)