Learn the Django User Authentication System
Giving users the ability to create an account they can sign into is a common function for many websites.
Users might need an account to participate in a comment thread, save their personal information, or transfer money. Whatever the use case may be, you need to build an authentication system that’s simple and safe for your users.
After reading this post, you should have a solid understanding of how Django thinks about authentication – from users, to groups, to permissions. You’ll also see how Django plays things safe where it can in order to help you avoid inadvertently contributing your users’ information to “Have I Been Pwned”.
For most websites, the basic entity of authentication is a user. A user is identified by some unique string, which is almost always an email address or username.
To prove someone is who they say they are, they must provide a password when creating an account, and again at any time they want to authenticate themselves. This should be familiar: you go through this kind of workflow any time you sign up for a service like Twitter or Netflix.
Django provides a
User model for creating and managing users. Django users have a username and password, but can also optionally have an email address and a first and last name:
from django.contrib.auth.models import User rafaela = User('rafaela', password='$uper$ecretpassword') # OR rafaela = User( 'Rafaela', firstname.lastname@example.org', password='$upser$ecretpassword', first_name='Rafaela', last_name='Lòpez', )
If you prefer to identify users by their email addresses, I recommend filling the username with the email address and keeping the address in the
Django provides a level of security when it comes to passwords. It has a built-in set of password validators, some of which are enabled by default in new projects. You can write your own validators to enforce any password rules you might need, but choose wisely – it’s been shown that many password rules lead to decreased security!
In addition to password validation, Django safely stores password information by default. Django salts and hashes passwords before storing them when a user is created, so their plaintext password is no longer available outside the context of the initial registration request or when they log in.
Storing passwords in plaintext is a surprisingly common oversight in the industry, so let Django be your safety rail here!
Like other models you may have used in Django, user objects can be queried and filtered and so on:
User objects have several other fields, attributes, and methods that will make sense in context as you read on about the Django features that involve users. Let’s start by looking at groups.
Django groups are, in short, a collection of users. Users can belong to multiple groups, but note that groups can’t belong to other groups – so it’s a shallow hierarchy. Groups are useful for creating “categories” of users for any number of things, like giving a particular group access to a feature on your website.
You can create a user group simply by giving it a name:
from django.contrib.auth.models import Group awesome_users = Group.objects.create(name='awesome_users')
User objects have a many-to-many relationship with groups, and you can access or set a user’s groups via its groups field:
The most common use of groups is pairing them with the idea of permissions.
Users shouldn’t have free reign to do whatever they like on your website. Any person could create an account and delete others’ posts!
Permissions are a generic way of determining if a Django user can perform a particular action. Permissions are often namespaced by the Django app and model in question, though they don’t have to be. You can check if a user (or a group they’re a member of) has permission to act on a particular object or type of object using
from treats.models import IceCream if rafaela.has_perm('treats.eat_ice_cream'): IceCream.objects.create(eater=rafaela)
Now we know there are users, who can belong to groups, and users and groups may have permissions to act on different types of model objects.
But how do you figure out which users are which?
Django can authenticate a user by checking a supplied set of credentials against the existing set of registered users. If a user matches, Django will return that user object. Otherwise, it will return
from django.contrib.auth import authenticate user = authenticate( username='rafaela', password='$uper$ecretpassword' )
You can use this to check if a user has supplied valid credentials, but this won’t keep a user logged in. In order to do that, you’ll want to use Django’s login method in addition to authenticating the user. The method accepts the current request object and the authenticated user object, and if successful, will redirect the user to a success page:
from django.contrib.auth import login ... if user: login(request, user) else: # invalid login, redirect to some kind of error page
When a user has successfully logged in, they’ll need a way to stay logged in. Logging in for every page load would be a bummer! Let’s go over how to do this.
Each time a user requests a page on your website, the incoming HTTP request sent from their browser gets processed by a number of layers, ultimately ending up in Django as an
If you’ve written a view before, you know that one of its expected arguments is an
HttpRequest object (usually called
request). If the Django authentication features are installed in your apps and middlewares (enabled by default for new projects), the request will have a reference to the user at
Django achieves this using sessions, which are bits of information stored in the database that are fetched based on a special cookie set in the user’s browser. When the user visits a page, the value from the cookie is used to check if there is an active session in the database. If so, the user is authenticated. If the session has expired or didn’t exist, the user will need to log in again.
For most use cases, you won’t need to interact with the session directly. However, you can get and set arbitrary data in the session for integrating with third party applications or doing more complicated things for your users that, for example, rely on actions they’ve taken so far during their current visit.
As you get started with Django authentication, you can think of sessions mostly as the factor that keeps your users logged in.
So, how can you tell if a user is logged in?
Handling authenticated users
The request object will always have a reference to a user, so you’ll need to be able to distinguish what kind of user they are. You can get a basic sense of this by checking the
request.user.is_authenticated attribute. This attribute is a boolean indicating whether the user is logged in or not.
If they’re not authenticated,
request.user will be an
AnonymousUser object, which means the person is not yet logged in or is perhaps a first-time visitor. You can use the
request.user.is_authenticated distinction for actions that only logged-in users are allowed to perform.
Django has a vast feature set for authenticating users and interacting with user objects to get things done.
This article has just scratched the surface; I encourage you to explore Django’s exceedingly thorough documentation to learn what else is possible.
Remember that Django tries hard to be secure and obvious by default, which gives you a great jumping-off point for a majority of projects. As is also customary in Django, everything can be customized or replaced to your liking as you advance. So go forth and create some users!