Skip to content
Django
9. User Authentication

User Authentication

In django there are many ways to authenticate users. Here are some of the most common ways to authenticate users in django:

We are assuming to use built-in User model or (Create a custom user model using AbstractBaseUser and BaseUserManager classes.)

  1. No built-in function used (Own Data Cleaning Process)
  2. Using built-in form
  3. Use third-party packages like django-allauth, django-rest-auth, django-rest-framework, etc.
  4. Use UserCreationForm.

The most common way is to use the built-in authentication system. This system is based on the User model and provides a way to authenticate users and manage their permissions.

1. No built-in function used

Register & Login Views

Create a view to register, login and logout a new user.

views.py
from django.shortcuts import render, redirect
from django.contrib import messages
from django.contrib.auth.models import User
from django.contrib.auth import logout, login, authenticate
 
def register(request):
    if request.method == 'POST':
        first_name = request.POST['first_name']
        last_name = request.POST['last_name']
        username = request.POST['username']
        email = request.POST['email']
        password = request.POST['password']
        password2 = request.POST['password2']
 
        if password == password2:
            if User.objects.filter(username=username).exists():
                messages.error(request, 'Username is already taken')
                return redirect('register')
            else:
                if User.objects.filter(email=email).exists():
                    messages.error(request, 'Email is already taken')
                    return redirect('register')
                else:
                    user = User.objects.create_user(username=username, email=email, password=password, first_name=first_name, last_name=last_name)
                    user.save()
                    # Login after register
                    # auth.login(request, user)
                    # messages.success(request, 'You are now logged in')
                    # return redirect('index')
                    messages.success(request, 'Account created successfully')
                    return redirect('login')
        else:
            messages.error(request, 'Passwords do not match')
            return redirect('register')
    else:
        return render(request, 'users/register.html')
 
def login(request):
    if request.method == 'POST':
        username = request.POST['username']
        password = request.POST['password']
        user = authenticate(request, username=username, password=password)
        if user is not None:
            login(request, user)
            return redirect('index')
        else:
            messages.error(request, 'Invalid username or password')
    return render(request, 'users/login.html')
 
def logout(request):
    """
    Handles the logout of the user.
    If the request method is POST, it logs out the user and redirects to the index page.
    If the request method is GET, it renders the logout page.
    """
    if request.method == 'POST':
        logout(request)
        messages.success(request, f'You have been logged out!')
        return redirect('index')
    return render(request, 'users/logout.html')

Register & Login Templates

register.html
<h2>Register</h2>
<form method="post">
    {% csrf_token %}
    <div>
        <label for="first_name">First Name</label>
        <input type="text" id="first_name" name="first_name" required>
    </div>
    <div>
        <label for="last_name">Last Name</label>
        <input type="text" id="last_name" name="last_name" required>
    </div>
    <div>
        <label for="username">Username</label>
        <input type="text" id="username" name="username" required>
    </div>
    <div>
        <label for="email">Email</label>
        <input type="email" id="email" name="email" required>
    </div>
    <div>
        <label for="password">Password</label>
        <input type="password" id="password" name="password" required>
    </div>
    <div>
        <label for="password2">Confirm Password</label>
        <input type="password" id="password2" name="password2" required>
    </div>
    <button type="submit">Register</button>
</form>
<small>Already have an account? <a href="{% url 'login' %}">Login</a></small>
login.html
<h2>Login</h2>
<form method="post">
    {% csrf_token %}
    <div>
        <label for="username">Username</label>
        <input type="text" id="username" name="username" required>
    </div>
    <div>
        <label for="password">Password</label>
        <input type="password" id="password" name="password" required>
    </div>
    <button type="submit">Login</button>
    <a href="{% url 'password_reset' %}">Forgot Password?</a>
</form>
Need an account? <a href="{% url 'register' %}">Register</a>

Adding Views to URLs

Add the following urls to the urls.py file.

urls.py
from django.urls import path
from . import views
 
urlpatterns = [
    path('register/', views.register, name='register'),
    path('login/', views.login, name='login'),
    path('logout/', views.logout, name='logout'),
]

2. Use third-party packages

You can also use third-party packages like django-allauth, django-rest-auth, django-rest-framework, etc.

3. Create a custom user model

4. Use UserCreationForm

Create a user registration form

  1. We are using default User model, but you can also create a custom user model using AbstractBaseUser and BaseUserManager classes. See

Creating a user registration form using UserCreationForm and UserChangeForm is very easy. You can use these forms to create and update users.

forms.py
from django.contrib.auth.models import User
from django.contrib.auth.forms import UserCreationForm, UserChangeForm
 
class UserForm(UserCreationForm):
    # You can add additional fields here
    class Meta:
        model = User
        # fields to be displayed in the form
        fields = ['username', 'email', 'password1', 'password2']
 
# With UserChangeForm
class UserUpdateForm(UserChangeForm):
    class Meta:
        model = User
        fields = ['username', 'email']
 
# Without UserChangeForm
class UserUpdateForm(forms.ModelForm):
    # You can add additional fields here
    class Meta:
        model = User
        # fields to be displayed in the form
        fields = ['username', 'email', 'first_name', 'last_name']
 

Creating views

Create a view to register, logout and delete_user a new user.

views.py
from django.shortcuts import render, redirect
from django.contrib import messages
from .forms import UserForm, UserUpdateForm
from django.contrib.auth.decorators import login_required
from django.contrib.auth import logout, login, authenticate
 
def register(request):
    if request.method == 'POST':
        form = UserForm(request.POST)
        if form.is_valid():
            form.save()
            username = form.cleaned_data.get('username')
            messages.success(request, f'Account created for {username}!')
            return redirect('login')
    else:
        form = UserForm()
    return render(request, 'users/register.html', {'form': form})
 
@login_required
def logout(request):
    """
    Handles the logout of the user.
    If the request method is POST, it logs out the user and redirects to the index page.
    If the request method is GET, it renders the logout page.
    """
    if request.method == 'POST':
        logout(request)
        messages.success(request, f'You have been logged out!')
        return redirect('index')
    return render(request, 'users/logout.html')
 
 
@login_required
def delete_user(request):
    """
    Handles the deletion of the user.
    If the request method is POST, it deletes the user and redirects to the index page.
    If the request method is GET, it renders the delete user page.
    """
    if request.method == 'POST':
        request.user.delete()
        messages.success(request, f'Your account has been deleted!')
        return redirect('index')
    return render(request, 'users/delete_user.html')
 

Add urls

  1. Add the following urls to the urls.py file.
urls.py
from django.urls import path
from . import views
from django.contrib.auth import views as auth_views
 
urlpatterns = [
    path('register/', views.register, name='register'),
    path('logout/', views.logout, name='logout'),
    path('delete_user/', views.delete_user, name='delete_user'),
    path('login/', auth_views.LoginView.as_view(template_name='users/login.html'), name='login'),
    path('password-reset/', auth_views.PasswordResetView.as_view(template_name='users/password_reset.html'), name='password_reset'),
    path('password-reset/done/', auth_views.PasswordResetDoneView.as_view(template_name='users/password_reset_done.html'), name='password_reset_done'),
    path('password-reset-confirm/<uidb64>/<token>/', auth_views.PasswordResetConfirmView.as_view(template_name='users/password_reset_confirm.html'), name='password_reset_confirm'),
    path('password-reset-complete/', auth_views.PasswordResetCompleteView.as_view(template_name='users/password_reset_complete.html'), name='password_reset_complete'),
]
 

Creating templates

Create a template for login, password reset, etc to render the form.

register.html
<h2>Register</h2>
<form method="post">
    {% csrf_token %}
    {{ form.as_p }}
    <button type="submit">Register</button>
</form>
<small>Already have an account? <a href="{% url 'login' %}">Login</a></small>
login.html
<h2>Login</h2>
<form method="post">
    {% csrf_token %}
    {{ form.as_p }}
    <button type="submit">Login</button>
    <a href="{% url 'password_reset' %}">Forgot Password?</a>
</form>
Need an account? <a href="{% url 'register' %}">Register</a>
password_reset.html
<h2>Password Reset</h2>
<form method="post">
    {% csrf_token %}
    {{ form.as_p }}
    <button type="submit">Request Reset Password</button>
</form>
password_reset_done.html
<h2>Password Reset Done</h2>
<p>We have sent you an email with a link to reset your password.</p>
password_reset_confirm.html
<h2>Password Reset Confirm</h2>
<form method="post">
    {% csrf_token %}
    {{ form.as_p }}
    <button type="submit">Reset Password</button>
</form>
password_reset_complete.html
<h2>Password Reset Complete</h2>
<p>Your password has been reset successfully.</p>
<a href="{% url 'login' %}">Login</a>
delete_user.html
<h2>Delete User</h2>
<p>Are you sure you want to delete your account?</p>
<p><strong>Username:</strong> {{ user.username }}</p>
<p><strong>Email:</strong> {{ user.email }}</p>
<form method="post">
    {% csrf_token %}
    <button type="submit">Delete</button>
    <a href="{% url 'index' %}">Cancel</a>
</form>
logout.html
<h2>Logout</h2>
<p>Are you sure you want to logout?</p>
{% if request.user.is_authenticated %}
    <form method="post">
        {% csrf_token %}
        <button type="submit">Logout</button>
        <a href="{% url 'index' %}">Cancel</a>
    </form>
{% else %}
    <a href="{% url 'login' %}">Login Again</a> |
    <a href="{% url 'register' %}">Register</a>
{% endif %}

Custom login view

  1. You can also add custom login view, password reset view, etc.
views.py
from django.contrib.auth import views as auth_views
 
def login(request):
    if request.method == 'POST':
        username = request.POST['username']
        password = request.POST['password']
        user = authenticate(request, username=username, password=password)
        if user is not None:
            login(request, user)
            return redirect('index')
        else:
            messages.error(request, 'Invalid username or password')
    return render(request, 'users/login.html')
 

Add settings

Add the following settings to the settings.py file.

settings.py
# Redirect to home page on login
LOGIN_REDIRECT_URL = 'index'
# Login URL for login_required decorator when user is not logged in
LOGIN_URL = 'login'
# Logout URL for logout view when user is logged in
LOGOUT_URL = 'logout'
 
 
# Email Password Reset Settings
EMAIL_BACKEND = 'django.core.mail.backends.smtp.EmailBackend'
EMAIL_HOST = 'smtp.gmail.com'
EMAIL_PORT = 587
EMAIL_USE_TLS =  True
EMAIL_HOST_USER = os.environ.get('EMAIL_USER')
EMAIL_HOST_PASSWORD = os.environ.get('EMAIL_PASS')

Add above environment variables to the .env file.

.env
EMAIL_USER = username
EMAIL_PASS = password