Building an authentication app with Django Authentication System | Python.
Published: 2022-12-16 14:47:29

---
title: Building an authentication app with Django Authentication System | Python.
published: true
date: 2022-09-05 00:02:55 UTC
tags: 
canonical_url: https://carlosmv.hashnode.dev/building-an-authentication-app-with-django-authentication-system-python
---

We can build an authentication for our projects using the Django authentication system.

Prerequisites:

- Python
- OOP
- Django Basic knowledge(Django templates, views, URLs, settings)

This is what the Django [documentation](https://docs.djangoproject.com/en/4.1/topics/auth/default/#all-authentication-views) says about its authentication system:

> Djangos authentication system in its default configuration. This configuration has evolved to serve the most common project needs, handling a reasonably wide range of tasks, and has a careful implementation of passwords and permissions. For projects where authentication needs differ from the default, Django supports extensive extension and customization of authentication.
> 
> Django authentication provides both authentication and authorization and is generally referred to as the authentication system, as these features are somewhat coupled.

We will use authentication views and built-in forms to create this app. The operations that this app will do are:

- User Registration
- Login
- Logout
- Password change

### Setup

Let's start creating a folder for our project, then we create a virtual environment, and activate it:

```
mkdir django_authentication
cd django auth
py -m venv venv

cd venv/Scripts
activate

```

Now we install Django:

```
pip install django

```

We create a django project:

```
django_admin startproject django_authentication
cd django_authentication

```

Now we create our app:

```
py manage.py startapp user_auth

```

We have to add our app to `django_authentication/settings.py` and the URLs our app will redirect the users when they login or logout :

settings.py

```
LOGIN_REDIRECT_URL = '/home'
LOGOUT_REDIRECT_URL = '/home'

INSTALLED_APPS = [
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',
    'user_auth',
]

```

After we add our app to `INSTALLED_APPS`, then we run migrations using the following command in our terminal:

```
py manage.py migrate

```

According to the doc:

> When django.contrib.auth is listed in your INSTALLED\_APPS setting, it will ensure that four default permissions add, change, delete, and view are created for each Django model defined in one of your installed applications.
> 
> These permissions will be created when you run manage.py migrate; the first time you run migrate after adding django.contrib.auth to INSTALLED\_APPS, the default permissions will be created for all previously-installed models, as well as for any new models being installed at that time. Afterward, it will create default permissions for new models each time you run manage.py migrate (the function that creates permissions is connected to the post\_migrate signal).

We are going to implement Authentication Views to handle login, logout, and password management, we need to add `django.contrib.auth.urls` to `django_authentication/urls.py`

django\_authentication/urls.py

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

urlpatterns = [
    path('admin/', admin.site.urls),
    path('users', include('django.contrib.auth.urls')),
]

```

This will include the following URL patterns:

```
users/login/ [name='login']
users/logout/ [name='logout']
users/password_change/ [name='password_change']
users/password_change/done/ [name='password_change_done']
users/password_reset/ [name='password_reset']
users/password_reset/done/ [name='password_reset_done']
users/reset/<uidb64>/<token>/ [name='password_reset_confirm']
users/reset/done/ [name='password_reset_complete']

```

We run the following command to run the server:

```
py manage.py runserver

```

In the `user_auth` directory, we create a folder to store our app's templates.

```
user_auth/
    __init__.py
    admin.py
    apps.py
    migrations/
    models.py
    templates/
        user_auth/
            home.html
            base.html
    tests.py
    urls.py
    views.py

```

### Home

views.py

```
from django.shortcuts import render

# Create your views here.

def home_page(request):
    return render (request,"user_auth/home.html")

```

Here we just write a function that will render `home.html`

We have to create an `urls.py` file inside our app's directory to add the URL of the views we will create.

user\_auth/urls.py

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

urlpatterns = [
    path('', views.home_page, name="home"),

]

```

Now we have to include user\_auth app URLs inside the project's `urls.py` file.

django\_authentication/urls.py

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

urlpatterns = [
    path('admin/', admin.site.urls),
    path('users', include('django.contrib.auth.urls')),
    path('home/', include('user_auth.urls')),

]

```

We create two templates. `base.html` where we are going to add the HTML and CSS code that will be inherited by other HTML files. And `home.html` that which will be the template of the home page.

base.html

```

<!doctype html>
<html lang="en">

<div class="topnav">
    <a href="{% url 'home' %}">Home</a>
     {% if user.is_authenticated %}
        <a href="{% url 'logout' %}">Logout</a>
      {% else %}
            <a href="{% url 'login' %}">Login</a>
      {% endif %}  
    <a href="{% url 'signup' %}">SingUp</a>
  </div>

    <div class="container">
        {% block content %}
        {% endblock content %}

    </div>

</body>

<html>

<style type="text/css">

.topnav {
  background-color: #333;
  overflow: hidden;
  position: fixed; 
  top: 0; 
  width: 100%; 
}

.topnav a {
  float: left;
  color: #f2f2f2;
  text-align: center;
  padding: 14px 16px;
  text-decoration: none;
  font-size: 17px;
  font-family: sans-serif;
}

/* Change the color of links on hover */
.topnav a:hover {
  background-color: #ddd;
  color: black;
}

.topnav a.active {
  background-color: #04AA6D;
  color: white;
}

body {
    background-color: #DEB887;
}
</style>

```

home.html

```
{% extends 'user_auth/base.html' %}

{% block content %}

  <body>
      <div class= "greeting">
          <h1>Hello</h1>

        <p> Welcome {{ user.username|default:'' }}, to the Our site</p>
      </div>

  </body>

<style>

 .greeting {
  color: #F0FFFF;
  text-align: center;
  font-family: sans-serif;
 } 

</style>

{% endblock content %}

```

![image.png](https://cdn.hashnode.com/res/hashnode/image/upload/v1662335090928/sfGam_qQB.png)

Inside templates/user\_auth, we create a folder named "registration". We create in it a template for login, signup, and a form\_base template. In the form\_base template, we add the HTML and CSS that will be inherited by the login and signup templates.

form\_base.html

The HTML and CSS were copied from [this](https://www.youtube.com/watch?v=llbtoQTt4qw) tutorial of Dennis Ivy.

```

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">

    <title>Django Auth</title>
    <link rel="preconnect" href="https://fonts.googleapis.com">
    <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
    <link href="https://fonts.googleapis.com/css2?family=Poppins:wght@300&display=swap" rel="stylesheet">

    <style>
        body {
            background-color: #DEB887;
            font-family: 'Poppins', sans-serif;
            padding-top: 50px;

        }
        h1,
        h2,
        h3,
        h4,
        h5,
        h6,
            {
            font-family:'Raleway', sans-serif;
        }

        a,
        p {
            color: #4b5156
        }

        .container{
            max-width: 550px;
            margin: auto;
            background-color: #FFEBCD;
            -webkit-box-shadow: 2px 2px 13px -4px rgba(0,0,0,0.21);
            box-shadow: 2px 2px 13px -4px rgba(0,0,0,0.21);

        }
        input {
            outline: none;
            border: none;
        }

        .header-bar {
            display:flex;
            justify-content:space-between;
            color:#fff;
            padding:10px;
            border-radius:5px 5px 0 0;
            background: #5F9EA0;
        }

        .header-bar a {
            color: rgb(247,247,247);
            text-decoration:none;

       }

        input[type=text],
        input[type=password],
        textarea {
            border: 1px solid #757575;
            border-radius: 5px;
            padding: 10px;
            width: 90%;
        }

        label {
            padding-top: 10px !important;
            display: block;
        }

        ::placeholder {
            font-weight: 300;
            opacity: 0.5;
        }

        .button {
            border: 1px solid #757575;
            background-color: #FFF;
            color: #EB796F;
            padding: 10px;
            font-size: 14px;
            border-radius: 5px;
            cursor: pointer;
            text-decoration: none;
        }

        .card-body {
            padding: 20px;
        }

        .topnav {
          background-color: #333;
          overflow: hidden;
          position: fixed; /* Set the navbar to fixed position */
          top: 0; /* Position the navbar at the top of the page */
          width: 100%; /* Full width */
        }

/* Style the links inside the navigation bar */
        .topnav a {
          float: left;
          color: #f2f2f2;
          text-align: center;
          padding: 14px 16px;
          text-decoration: none;
          font-size: 17px;
          font-family: sans-serif;
        }

/* Change the color of links on hover */
.topnav a:hover {
  background-color: #ddd;
  color: black;
}

    </style>

</head>
<body>
    <div class="topnav">
      <a href="{% url 'home' %}">Home</a>
       {% if user.is_authenticated %}
          <a href="{% url 'logout' %}">Logout</a>
        {% else %}
              <a href="{% url 'login' %}">Login</a>
        {% endif %}  
      <a href="{% url 'signup' %}">SingUp</a>
    </div>

    <div class="container">
        {% block content %}
        {% endblock content %}

    </div>

</body>
</html>

```

### SignUp

Views.py

```
from django.shortcuts import render
from django.urls import reverse_lazy
from django.contrib.auth.forms import UserCreationForm, AuthenticationForm
from django.views.generic.edit import CreateView

...

class SignUp(CreateView):
    form_class = UserCreationForm
    success_url = reverse_lazy("login")
    template_name = "user_auth/registration/signup.html"

```

We create a child class from `CreateView`. This class displays a form for creating an object, redisplaying the form with validation errors (if there are any), and saving the object. For this class, we give `UserCreationForm` as a value to `form_class`, this form creates a user, with no privileges, from the given username and password.

After the signup, the user will be taken to the login page. To `template_name` we give as a value the location of the template for this view.

signup.html

```
{% extends 'user_auth/registration/form_base.html' %}

{% block content %}
<div class="header-bar">
    <h1>Sign Up</h1>
</div>

<div class="card-body">
    <form method="POST">
        {% csrf_token %}
        <label>{{form.username.label}}</label>
        {{form.username}}

        <label>{{form.password1.label}}</label>
        {{form.password1}}

        <label>{{form.password2.label}}</label>
        {{form.password2}}
        <input style="margin-top:10px;" class="button" type="submit" value="Register">
    </form>
    <p>Already have an account?<a href="{% url 'login' %}">Login</a></p>
</div>
{% endblock %}

```

![image.png](https://cdn.hashnode.com/res/hashnode/image/upload/v1662335563967/wclKFdjZh.png)

### Login

```
from django.shortcuts import render
from django.urls import reverse_lazy
from django.contrib.auth.forms import UserCreationForm, AuthenticationForm
from django.views.generic.edit import CreateView

...

class Login(LoginView):
    form_class = AuthenticationForm
    template_name = "user_auth/registration/login.html"

```

We create a child class from `LoginView`. And use `AuthenticationForm` as a `form_class` which is a form for logging a user in. Here we do not define `success_url` because it is already defined in `settings.py`.

According to the doc, this is what `LoginView` does:

> Heres what `LoginView` does:
> 
> If called via GET, it displays a login form that POSTs to the same URL. More on this in a bit.
> 
> If called via POST with user submitted credentials, it tries to log the user in. If login is successful, the view redirects to the URL specified in next. If next isnt provided, it redirects to settings.LOGIN\_REDIRECT\_URL (which defaults to /accounts/profile/). If login isnt successful, it redisplays the login form.
> 
> Its your responsibility to provide the HTML for the login template , called registration/login.html by default. This template gets passed four template context variables:
> 
> form: A Form object representing the AuthenticationForm.
> 
> next: The URL to redirect to after successful login. This may contain a query string, too.
> 
> site: The current Site, according to the SITE\_ID setting. If you dont have the site framework installed, this will be set to an instance of RequestSite, which derives the site name and domain from the current HttpRequest.
> 
> site\_name: An alias for site.name. If you dont have the site framework installed, this will be set to the value of request.META['SERVER\_NAME']. For more on sites, see The sites framework.
> 
> If youd prefer not to call the template registration/login.html, you can pass the template\_name parameter via the extra arguments to the as\_view method in your URLconf. For example, this URLconf line would use myapp/login.html instead:
> 
> ```
> path('accounts/login/', auth_views.LoginView.as_view(template_name='myapp/login.html')),
> 
> ```

login.html

```
{% extends 'user_auth/registration/form_base.html' %}

{% block content %}
  <div class="header-bar">
    <h1>Login</h1>
</div>

<div class="card-body">
    <form method="POST">
        {% csrf_token %}
        {{form.as_p}}
        <input class="button" type="submit" value="Login">
    </form>
    <p> Don't have an account?<a href="{% url 'signup' %}">Register</a></p>
</div>

{% endblock %}

```

![image.png](https://cdn.hashnode.com/res/hashnode/image/upload/v1662335473234/Xtyj-rffM.png)

### Password Change

views.py

```
from django.shortcuts import render
from django.urls import reverse_lazy
from django.contrib.auth.forms import UserCreationForm, AuthenticationForm, PasswordChangeForm
from django.views.generic.edit import CreateView
from django.contrib.auth.views import LoginView, LogoutView, PasswordChangeView

...

class PasswordChange(PasswordChangeView):
    form_class = PasswordChangeForm
    template_name = "user_auth/registration/password_change_form.html"

```

The `PasswordChangeView` allows the user to change this password. The `PasswordChangeForm` is a form for allowing a user to change their password.

password\_change.html

```
{% extends 'user_auth/registration/form_base.html' %}

{% block content %}
  <div class="header-bar">
    <h1>Password Change</h1>
</div>

<div class="card-body">
    <form method="POST">
        {% csrf_token %}
        {{form.as_p}}
        <input class="button" type="submit" value="Login">
    </form>
</div>

{% endblock %}

```

![image.png](https://cdn.hashnode.com/res/hashnode/image/upload/v1662335750307/huyN1YU4T.png)

home.html

```
{% extends 'user_auth/base.html' %}

{% block content %}

  <body>
      <div class= "greeting">
        <h1> Welcome {{ user.username|default:'' }}, to the Django Auth site.</h1>
      {% if user.is_authenticated %}
        <p> Change you password<a href="{% url 'password_change' %}"> Here</a></p>
      {% endif %}    
      </div>

  </body>

<style>

 .greeting {

  color: #F0FFFF;
  text-align: center;
  font-family: sans-serif;
 } 

</style>

{% endblock content %}

```

![image.png](https://cdn.hashnode.com/res/hashnode/image/upload/v1662335316838/do8JjbCQH.png)

### Conclusion

Django allows us to create authentication for our projects very easy using its class base views. Also, we can implement a password reset with email using `PasswordResetView` and `PasswordResetForm`. This is an advantage because it allows us to invest more time in our app's business logic.

Thank you for taking the time to read this article.

If you have any recommendations about other packages, architectures, how to improve my code, my English, or anything; please leave a comment or contact me through [Twitter](https://twitter.com/Carlos_marcv), [LinkedIn](https://www.linkedin.com/in/carlos-marcano-a2135a134/).

The source code is [here](https://github.com/carlosm27/blog/tree/main/django_authentication).

### References

- [Django Authentication System documentation](https://docs.djangoproject.com/en/4.1/topics/auth/default/#django.contrib.auth.forms.PasswordChangeForm)

- [Django To Do List App With User Registration and Login](https://www.youtube.com/watch?v=llbtoQTt4qw)

- [How To Build Your Own Login and Registration System in Django](https://medium.com/python-in-plain-english/how-to-build-your-own-login-and-registration-system-in-django-ae39a726cb8a?source=list-af25b2dc811b--------8-------61c4f7f1bece---------------------)