---
title: Implementing Custom Authentication in Django
description: When all other options fail, make your own.
image: https://pages.melio.ai/hubfs/Imported_Blog_Media/cover-Apr-03-2024-12-39-02-1885-PM.webp
---

[![Melio AI](https://pages.melio.ai/hs-fs/hubfs/logo-1.png?width=208&height=65&name=logo-1.png)](https://pages.melio.ai/)

- [Home](https://pages.melio.ai/)
- [Services](https://pages.melio.ai/services) 
    - [Consulting](https://pages.melio.ai/consulting)
    - [Retainer](https://pages.melio.ai/retainer)
    - [AI As A Service](https://pages.melio.ai/ai-as-service)
    - [Fluid Assessment](https://pages.melio.ai/fluid-assessment)
    - [Workshops](https://pages.melio.ai/workshops)
- [Products](https://pages.melio.ai/products) 
    - [Kaidex](https://pages.melio.ai/kaidex)
    - [RubrlQ](https://pages.melio.ai/rubrliq)
- [About](https://pages.melio.ai/about)
- [Case Studies](https://pages.melio.ai/case-studies)
- [Insights](https://pages.melio.ai/insights)
- [Contact](https://pages.melio.ai/contact)

[Home](https://pages.melio.ai/)  › [Insights](https://pages.melio.ai/insights)  › **Implementing Custom Authentication in Django**

# Implementing Custom Authentication in Django

 Author Details  15 September 2026

## In this article

![](https://pages.melio.ai/hubfs/Imported_Blog_Media/cover-Apr-03-2024-12-39-02-1885-PM.webp)

> When all other options fail, make your own.

![](https://pages.melio.ai/hubfs/Imported_Blog_Media/cover-Apr-03-2024-12-39-02-1885-PM.webp)

###### Photo by pch.vector from Freepik.

## Introduction

This tutorial will take you from absolute zero to a fully-working custom authentication system in Django.

Django comes with built-in authentication backends that make it really easy to get started and meet most projects’ needs. There are also a slew of Django apps (such as [django-allauth](https://django-allauth.readthedocs.io/)) that have been written to integrate with identity providers such as Google and GitHub.

But what do you do when even these don’t meet your needs?

For example, I was recently attempting to integrate a Django application with a Keycloak backend, and found that existing libraries such as:

1. [django-keycloak](https://django-keycloak.readthedocs.io/en/latest/)
2. [django-keycloak-auth](https://github.com/marcelo225/django-keycloak-auth)
3. [django-allauth](https://django-allauth.readthedocs.io/)

either did not work as advertised (though PEBKAC errors are not unlikely here) or did not work in exactly the way I needed. My only option was creating my own custom authentication backend. This sounds like a complicated thing to do, but is actually really simple.

I’ve included a TL;DR right up front if you already know a bit about Django. The code is also [on GitHub](https://github.com/bradleymarques/custom-authentication-backend-django).

## TL;DR - Just Gimme the Answer

In a rush? Here’s the answer:

### settings.py

```
# ./mysite/settings.py  INSTALLED_APPS = [  # ... other apps  "django.contrib.auth",  # ... other apps  "my_custom_authentication", # Or whatever your app is called ]  # ...  AUTHENTICATION_BACKENDS = [  "my_custom_authentication.backends.MyCustomAuthenticationBackend", ] 
```

### my\_custom\_authentication\_backend.py

```
# ./my_custom_authentication/backends/my_custom_authentication_backend.py from django.contrib.auth.backends import BaseBackend from django.contrib.auth import get_user_model # Important for custom User objects   class MyCustomAuthenticationBackend(BaseBackend):  def authenticate(self, request, username=None, password=None):  user = # ... some custom logic such as an API call to an identity provider   # Return None if authentication fails, or a User object if authentication succeeds  return user or None 
```

If the above doesn’t make much sense, follow the complete tutorial below:

## Starting the application

### Poetry

Let’s start by creating a [Poetry](https://python-poetry.org/) (you could simply use `pip` if you prefer) configuration file for the project. If not installed, please [install Poetry](https://python-poetry.org/docs/#installation).

```
poetry init 
```

Fill in your details, and choose to not define your dependencies interactively. Once complete, open the `pyproject.toml` file and ensure that it has content similar to:

```
[tool.poetry] name = "your-application-name-here" version = "0.1.0" description = "" authors = ["Your Name <your-email@example.com>"]  [tool.poetry.dependencies] python = "^3.10" Django = "^4.0.5"  [tool.poetry.dev-dependencies]  [build-system] requires = ["poetry-core>=1.0.0"] build-backend = "poetry.core.masonry.api" 
```

Then open up a Poetry virtual environment and install the dependencies in it:

```
poetry shell poetry install poetry update 
```

Check the installation of Django:

```
python -m django --version # 4.0.5 
```

### Starting the Django Project and App

If you don’t already know, Django has the concept of “projects” and pluggable “apps” that you install into the project. Let’s start the project by running:

```
django-admin startproject mysite . 
```

Note the trailing dot in the above command.

Now we can go ahead and create the django app. We’ll make this application reusable, so go ahead and give it a name that suits your needs. For example, if your ultimate goal is to authenticate with `Dex` or `Keycloak` call it something like `dex_authentication` or `keycloak_authentication`. As a way of example, I am just going to do an in-memory authentication, so I will run:

```
python manage.py startapp in_memory_authentication 
```

At this stage, we should already be able to start the Django application. Run:

```
python manage.py runserver 
```

Navigate to the URL shown (usually [http://localhost:8000](http://localhost:8000)) and you should see a lovely rocket blasting off:

![](https://pages.melio.ai/hubfs/Imported_Blog_Media/rocket_ship.webp)

###### The running Django application

## Understanding Django’s Default User Authentication

If don’t know already and you’re interested how Django would do normal User authentication, check out [this great tutorial](https://learndjango.com/tutorials/django-login-and-logout-tutorial). Because it’s already covered so well there, I won’t cover it here, and rather just proceed to customizing our user authentication.

## Implementing a Login Page

The first thing we’d need to do is include a login page for our Users to authenticate. Go ahead and open the `./mysite/urls.py` file. Add the following marked lines to it:

```
from django.urls import path, include # Added "include" here  urlpatterns = [  path('admin/', admin.site.urls),  path("accounts/", include("django.contrib.auth.urls")), # Added this line ] 
```

What this does is mount the default Views provided in the `django.contrib.auth` app to a URL of our choice (in this case `accounts/`).

Let’s run the server again (`python manage.py runserver`) and this time navigate to [http://localhost:8000/accounts/login](http://localhost:8000/accounts/login). Oops! You should get an error page saying:

```
TemplateDoesNotExist at /accounts/login/ 
```

That’s because we need to define an HTML Template for the login page. Do this by creating the following folders in the root folder (i.e. NOT the `mysite` nor `in_memory_authentication` folders).

```
mkdir templates mkdir templates/registration 
```

Then create a `login.html` file in the `templates/registration` folder with the following content:

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

One final thing we need to do is configure our Django project to look for templates in this folder structure. Open up the `settings.py` again, and look for the `TEMPLATES` constant:

```
TEMPLATES = [  {  # ...  'DIRS': [],  # ...  }, ] 
```

Change the `DIRS` value from an empty list to:

```
TEMPLATES = [  {  # ...  'DIRS': [BASE_DIR / "templates"],  # ...  }, ] 
```

This instructs our Django project to look for templates in folders called `templates`.

Restart the server and navigate to [http://localhost:8000/accounts/login](http://localhost:8000/accounts/login) again. You should see a beautiful login form:

![](https://pages.melio.ai/hubfs/Imported_Blog_Media/login.webp)

###### The login form. Hey, if you wanted a tutorial on CSS you came to the wrong place.

Attempting to login with details will not work, obviously, for a number of reasons:

1. We have not yet migrated our database, so have no User table
2. Even if we had migrated our database, we have not created any User records.

Let’s correct the first problem now. First, stop the server and then run the following command to migrate the database:

```
python manage.py migrate 
```

> **Huh?** You may be wondering at this stage where the definition of our User table comes from. It comes from the `django.contrib.auth` app which is by default in the `INSTALLED_APPS` in `settings.py`.

Rerun the server, and try to login with any details. You should see a little message reading: `Please enter a correct username and password. ...`

## Writing a Custom Authentication Backend

Let’s now assume that we want to always allow access to the site with a hard-coded user with the credentials:

- Username: `let_me_in`
- Password: `please`

Of course you would never want to do this, but it does illustrate how to create the custom Django authentication backend.

First, let’s create a new folder in our `./in_memory_authentication` folder called `backends`. Like any Python module, it will need a `__init__.py` file, so create that, and go ahead and create a file for the actual backend. I called mine `./in_memory_authentication/backends/in_memory_authentication_backend.py`.

Let’s populate this file now with the following:

```
# ./in_memory_authentication/backends/in_memory_authentication_backend.py  from django.contrib.auth.backends import BaseBackend   class InMemoryAuthenticationBackend(BaseBackend):  def authenticate(self, request, username=None, password=None):  return None 
```

You will notice that I’m extending the `BaseBackend` auth backend. It has a single function `authenticate` that takes in the request, as well as `username` and `password`. The function should respond in the following way:

- Should return `None` if the authentication attempt fails.
- Should return an instance of the User model if the authentication attempt succeeds.

Let’s export this in the newly-created `__init__.py` file:

```
# ./in_memory_authentication/backends/__init__.py  from .in_memory_authentication_backend import InMemoryAuthenticationBackend 
```

Let’s also “register” this backend with our Django app. Open up the `settings.py` file and make the following two changes:

```
INSTALLED_APPS = [  # ... other apps  "django.contrib.auth",  # ... other apps  "in_memory_authentication", # Install our new app here ]  # ...  # Add this to the bottom of the file:  AUTHENTICATION_BACKENDS = [  "in_memory_authentication.backends.InMemoryAuthenticationBackend", ] 
```

Now if we attempt to login, our custom authentication backend will be called. Of course, we still won’t be able to login since we are always returning `None` from our `authenticate` method.

Let’s change that now.

Open up `./in_memory_authentication/backends/in_memory_authentication_backend.py` and alter it to:

```
# ./in_memory_authentication/backends/in_memory_authentication_backend.py import uuid  from django.contrib.auth.backends import BaseBackend from django.contrib.auth.models import User   class InMemoryAuthenticationBackend(BaseBackend):  def authenticate(self, request, username=None, password=None):  # Replace this silly logic with whatever you need:  if username == "let_me_in" and password == "please":   # Create a new user  new_user = User(username=uuid.uuid4().__str__())  new_user.set_unusable_password()  new_user.save()   return new_user  else:  return None 
```

This is some silly logic, and you should replace it with what you need, but it creates a new User and returns that user, thus logging them in. You should replace this with things like a call to a Dex or Keycloak API, for example.

If you now login with the credentials `let_me_in` and `please`, you should successfully authenticate.

Of course, we have not built any pages after the user logs in, so you should get a `404 Page not found` error at this stage.

## Catering for Custom User Classes

You’ll notice above that I am returning an instance of the `django.contrib.auth.models.User` class. However, not all Django projects will use this, and it is therefore better to make use of the `get_user_model()` function to find what class this project uses. Further, we can extract the finding of the user into a method:

```
# ./in_memory_authentication/backends/in_memory_authentication_backend.py import uuid  from django.contrib.auth.backends import BaseBackend from django.contrib.auth import get_user_model   class InMemoryAuthenticationBackend(BaseBackend):  def authenticate(self, request, username=None, password=None):  return self.find_user(username, password)   # Replace this silly logic with something better, such as an API call to  # an identity provider:  def find_user(self, username, password):  if username == "let_me_in" and password == "please":  user_klass = get_user_model()  new_user = user_klass(username=uuid.uuid4().__str__())  new_user.set_unusable_password()  new_user.save()  return new_user  else:  return None 
```

That’s it! We’ve successfully created and used our own custom authentication backend in Django.

## Explore related content

![Launching Into Uncertainty](https://pages.melio.ai/hubfs/Imported_Blog_Media/cover-Apr-03-2024-12-39-02-1885-PM.webp)

 Articles

### Launching Into Uncertainty - 6 Smart Steps to Future-Proof Your Business

 Practical steps for navigating uncertainty, building resilient technology strategies and preparing your organisation for what comes next. 

 Read the Full Story

 **Reading time:**  6 minutes

 03 April 2024

![What the Ops are you talking about?](https://pages.melio.ai/hubfs/Imported_Blog_Media/cover-Apr-03-2024-12-39-02-1885-PM.webp)

 Articles

### What the Ops are you talking about?

 Understanding the changing world of modern operations, MLOps and the systems required to move AI successfully into production. 

 Read the Full Story

 **Reading time:**  8 minutes

 03 April 2024

![Implementing Custom Authentication in Django](https://pages.melio.ai/hubfs/Imported_Blog_Media/cover-Apr-03-2024-12-39-02-1885-PM.webp)

 Articles

### Implementing Custom Authentication in Django

 A practical look at implementing custom authentication in Django and creating secure application experiences. 

 Read the Full Story

 **Reading time:**  7 minutes

 03 April 2024

[![logo-long-dark](https://pages.melio.ai/hubfs/logo-long-dark.webp)](https://pages.melio.ai/)

We build and run production AI systems for enterprise – agentic platforms, MLOps infrastructure, and document intelligence – for financial services, healthcare, manufacturing and technology leaders. An AWS Advanced Tier Partner with AI Competency, we take AI from pilot to production, and productize what we learn through Highwind, our AI-as-a-Service platform.

<https://www.linkedin.com/company/melio-consulting/> <https://www.instagram.com/melio.ai/> <https://x.com/MelioAi> <https://github.com/melio-consulting>

Company

[Home](https://pages.melio.ai/) [Services](https://pages.melio.ai/services) [Products](https://pages.melio.ai/products) [About](https://pages.melio.ai/about) [Case Studies](https://pages.melio.ai/case-studies) [Insights](https://pages.melio.ai/insights) [Contact](https://pages.melio.ai/contact)

Get in touch

 Workshop17 The Bank  
24 Cradock Avenue, Johannesburg 

[poke@melio.ai](mailto:poke@melio.ai)

© 2026 melio.ai. All rights reserved.

[Privacy Policy](https://pages.melio.ai/privacy-policy) [PAIA Manual](https://pages.melio.ai/paia-manual)

 Cookie Settings

 Built on AWS · Powered by humans who actually give a damn.

```json
{
  "@context" : "https://schema.org",
  "@type" : "BlogPosting",
  "author" : {
    "@type" : "Person",
    "name" : "Admin",
    "url" : "https://pages.melio.ai/insights/author/admin"
  },
  "dateModified" : "2026-09-15T17:26:36.548Z",
  "datePublished" : "2026-09-15T17:26:36.000Z",
  "headline" : "Implementing Custom Authentication in Django",
  "image" : [ "https://pages.melio.ai/hubfs/Imported_Blog_Media/cover-Apr-03-2024-12-39-02-1885-PM.webp" ],
  "mainEntityOfPage" : {
    "@id" : "https://pages.melio.ai/insights/django-custom-authentication-backends",
    "@type" : "WebPage"
  },
  "publisher" : {
    "@type" : "Organization",
    "logo" : {
      "@type" : "ImageObject",
      "url" : "https://pages.melio.ai/hubfs/melio-horizontal-white-1280-1.png"
    },
    "name" : "Melio AI"
  }
}
```