Configuring proper user authentication in a web application is tough. There are a lot of steps involved–login, logout, sign up, password reset, etc–and many chances to make a mistake. Fortunately Django comes with a powerful built-in user authentication system that makes things much easier.

This tutorial covers how to implement a login and logout page with the default Django User model. In Part 2: Signup we will review how to register a new user with a sign up page and in Part 3: Password Reset how configure a password reset sequence.

Complete source code can be found on Github.

Setup

Let’s start by creating a new Django project. We can do all of the normal configuration from the command line:

  • create a new virtual environment called users
  • install Django
  • create a new Django project called my_project
  • create a new Sqlite database with migrate
  • run the local server

Here are the commands to run:

$ python3 -m venv ~/.virtualenvs/users
$ source ~/.virtualenvs/users/bin/activate
(users) $ pip install django
(users) $ django-admin.py startproject my_project .
(users) $ ./manage.py migrate
(users) $ ./manage.py runserver

If you navigate to http://127.0.0.1:8000 you’ll see the friendly Django welcome screen.

Django welcome page

The Django auth app

Django automatically installs the auth app when a new project is created. If you look in the settings.py under INSTALLED_APPS, you can see auth is one of several built-in apps Django has automatically installed.

INSTALLED_APPS = [
    'django.contrib.admin',
    'django.contrib.auth', # Yoohoo!!!!
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',
]

To use the auth app we need to add it to our project-level urls.py file. Note on the top line we’re also importing include from django.conf.urls:

# my_project/urls.py
from django.conf.urls import include, url
from django.contrib import admin

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

I’ve chosen to include the auth app at users/ but you can use almost any url pattern you want. Typically it’s either users/, accounts/, or the empty string '^'.

The auth app we’ve now included automatically provides us with several authentication views and URLs for handling login, logout, and password management.

The URLs provided by auth are:

^login/$ [name='login']
^logout/$ [name='logout']
^password_change/$ [name='password_change']
^password_change/done/$ [name='password_change_done']
^password_reset/$ [name='password_reset']
^password_reset/done/$ [name='password_reset_done']
^reset/(?P<uidb64>[0-9A-Za-z_\-]+)/(?P<token>[0-9A-Za-z]{1,13}-[0-9A-Za-z]{1,20})/$ [name='password_reset_confirm']
^reset/done/$ [name='password_reset_complete']

There are associated auth views for each URL pattern, too. That means we only need to create a template to use each!

Login Page

Let’s make our login page! Django by default will look within a templates folder called registration for auth templates. And the login template is called…login.html.

Create a new directory called registration and the requisite login.html file within it. From the command line type Control-C to quit our local server and enter the following commands:

(users) $ mkdir templates
(users) $ mkdir templates/registration
(users) $ touch templates/registration/login.html

Then include the following template code in our login.html file:

<!-- templates/registration/login.html -->
<h2>Login</h2>
<form method="post">
  {% csrf_token %}
  {{ form.as_p }}
  <button type="submit">Login</button>
</form>

This is a standard Django form using POST to send data and {% csrf_token %} tags for security concerns, namely to prevent a XSS Attack. The form’s contents are outputted between paragraph tags thanks to {{ form.as_p }} and then we add a “submit” button.

Next update our settings.py file to tell Django to look for a templates folder at the project level. Update the DIRS setting within TEMPLATES as follows. This is a one-line change.

# settings.py
TEMPLATES = [
    {
        ...
        'DIRS': [
            os.path.join(BASE_DIR, 'templates')
        ],
        ...

    },
]

Our login functionality now works but to make it better we should specify where to redirect the user upon a successful login. In other words, once a user has logged in, where should they be sent on the site? We use the LOGIN_REDIRECT_URL setting to specify this route. At the bottom of the settings.py file add the following to redirect the user to the homepage.

# my_project/settings.py
LOGIN_REDIRECT_URL = '/'

We’re actually done at this point!

If you now start up the Django server again with ./manage.py runserver and navigate to our login page at http://127.0.0.1:8000/users/login/ you’ll see the following.

Login page

Create users

But there’s one missing piece: we haven’t created any users yet. Let’s quickly do that by making a superuser account from the command line. Quit the server with Control-c and then run the command ./manage.py createsuperuser. Answer the prompts and note that your password will not appear on the screen when typing for security reasons.

(users) $ ./manage.py createsuperuser
Username (leave blank to use 'wsv'):
Email address: [email protected]
Password:
Password (again):
Superuser created successfully.

Now spin up the server again with ./manage.py runserver and refresh the page at http://127.0.0.1:8000/users/login/. Enter the login info for your just-created user.

Homepage error

We know that our login worked because we were redirected to the homepage, but we haven’t created it yet so we see the error Page not found. Let’s fix that!

Create a homepage

We want a simple homepage that will display one message to logged out users and another to logged in users.

First quit the local server with Control-c and then create new base.html and home.html files. Note that these are located within the templates folder but not with templates/registration/ where Django auth looks by default for user auth templates.

(users) $ touch templates/base.html
(users) $ touch templates/home.html

Add the following code to each:

<!-- templates/base.html -->
<!DOCTYPE html>
<html>
<head>
  <meta charset="utf-8">
  <title>{% block title %}Django Auth Tutorial{% endblock %}</title>
</head>
<body>
  <main>
    {% block content %}
    {% endblock %}
  </main>
</body>
</html>
<!-- templates/home.html -->
{% extends 'base.html' %}

{% block title %}Home{% endblock %}

{% block content %}
{% if user.is_authenticated %}
  Hi {{ user.username }}!
{% else %}
  <p>You are not logged in</p>
  <a href="{% url 'login' %}">login</a>
{% endif %}
{% endblock %}

While we’re at it, we can update login.html too to extend our new base.html file:

<!-- templates/registration/login.html -->
{% extends 'base.html' %}

{% block title %}Login{% endblock %}

{% block content %}
<h2>Login</h2>
<form method="post">
  {% csrf_token %}
  {{ form.as_p }}
  <button type="submit">Login</button>
</form>
{% endblock %}

Now update our urls.py file so we display the homepage. On the third line, import TemplateView and then add a urlpattern for it.

# my_project/urls.py
from django.conf.urls import include, url
from django.contrib import admin
from django.views.generic.base import TemplateView

urlpatterns = [
    url(r'^$', TemplateView.as_view(template_name='home.html'), name='home'),
    url(r'^admin/', admin.site.urls),
    url(r'^users/', include('django.contrib.auth.urls')),
]

And we’re done. If you start the Django server again with ./manage.py runserver and navigate to the homepage at http://127.0.0.1:8000/ you’ll see the following:

Homepage logged in

It worked! But how do we logout? The only option currently is to go into the admin panel at http://127.0.0.1:8000/admin/ and click on the “Logout” link in the upper right corner.

Admin page logout link

This will log us out as seen by the redirect page:

Admin page logged out

If you go to the homepage again at http://127.0.0.1:8000/ and refresh the page, we can see we’re logged out.

Home page logged out

Let’s add a logout link to our page so users can easily toggle back and forth between the two states. Fortunately the Django auth app already provides us with a built-in url and view for this. And if you think about it, we don’t need to display anything on logout so there’s no need for a template. All really we do after a successful “logout” request is redirect to another page.

So let’s first add a link to the built-in logout url in our base.html file:

<!-- templates/home.html-->
{% extends 'base.html' %}

{% block title %}Home{% endblock %}

{% block content %}
{% if user.is_authenticated %}
  Hi {{ user.username }}!
  <p><a href="{% url 'logout' %}">logout</a></p>
{% else %}
  <p>You are not logged in</p>
  <a href="{% url 'login' %}">login</a>
{% endif %}
{% endblock %}

Then update settings.py with our redirect link which is called LOGOUT_REDIRECT_URL. Add it right next to our login redirect so the bottom of the settings.py file should look as follows:

# my_project/settings.py
LOGIN_REDIRECT_URL = '/'
LOGOUT_REDIRECT_URL = '/'

Actually, now that we have a homepage view we should use that instead of our current hardcoded approach. What’s the url name of our homepage? It’s home, which we named in our my_project/urls.py file:

# my_project/urls.py
    ...
    url(r'^$', TemplateView.as_view(template_name='home.html'), name='home'),
    ...

So we can replace '/' with home at the bottom of the settings.py file:

# my_project/settings.py
LOGIN_REDIRECT_URL = 'home'
LOGOUT_REDIRECT_URL = 'home'

Now refresh the homepage you’ll see it now has a “logout” link for logged in users.

Homepage logout link

Clicking it takes you back to the homepage with a “login” link.

Homepage logged out

Conclusion

With very little code we have a robust login and logout authentication system. It probably feels a bit like magic since the auth app did much of the heavy lifting for us. One of the nice things about Django is while it provides a lot of functionality out-of-the-box, it’s designed to be customizable too.

In the next post, Django User Authentication Tutorial Part 2: Signup, we’ll learn how to add a signup page to register new users.




If you’d like to learn more about Django and build step-by-step multiple web applications, check out the free online book I wrote Django For Beginners.