User registration and authentication is one of the most essential components of a web application. This tutorial deals with setup, configuration, and customization of django-allauth along with advanced tweaks and social login setup for your django web app. This tutorial intends to serve as a guide for new users who want to get started quickly with django-allauth and make useful customizations along the way without much pain.
Why this guide?
django-allauth
is a very well written library thanks to Raymond Penners. However, it can be overwhelming to a django
novice or advanced users using django-allauth
for the first time. Although it is well documented, due to time and resource constraints of the developers involved, there has not been many articles and in-depth tutorials on the library. So this tutorial tries to solve that problem by making a comprehensive guide to get started quickly and also learn about advanced customization.
Basic Setup
You can download the files used in the tutorial to get a head start. The steps below guide you through the setup in detail.
Create a Django project if you already don’t have one.
Install
django-allauth
using the commandpip install django-allauth
Add,allauthallauth.account
, allauth.socialaccount
and all the social login features you need to INSTALLED_APPS
section in settings.py
.
You can view the entire list of supported API's here.
The social login feature is described later in the post. You can scroll down to that subheading if you would like to just read that. After you configure your installed apps section, it should be similar to the code given below.
INSTALLED_APPS = [
'django.contrib.admin',
'allauth',
'allauth.account',
'allauth.socialaccount',
'allauth.socialaccount.providers.google',
'allauth.socialaccount.providers.facebook',
'django.contrib.auth',
'django.contrib.sites',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
]
Configure the template
context processor settings in settings.py
and also add the url pattern in the project’s urls.py
.
TEMPLATES = [
{
'BACKEND': 'django.template.backends.django.DjangoTemplates',
'DIRS': [
os.path.normpath(os.path.join(BASE_DIR, 'templates')),
],
'APP_DIRS': True,
'OPTIONS': {
'context_processors': [
'django.template.context_processors.debug',
'django.template.context_processors.request',
'django.contrib.auth.context_processors.auth',
'django.contrib.messages.context_processors.messages',
'django.template.context_processors.request',
],
},
},
]
Add the following authentication backend.
AUTHENTICATION_BACKENDS = (
'django.contrib.auth.backends.ModelBackend',
'allauth.account.auth_backends.AuthenticationBackend',
)
Copy the template files from the django-allauth
repository or you can also use my custom repository(I have made some modifications and some good structuring) and paste it in the folder templates
in your project directory.
Add the allauth urls in urls.py
of your main project directory. After adding the allauth urls the urls file should look similar to,
from django.contrib import admin
from django.urls import path
from django.conf.urls import url, include
urlpatterns = [
path('admin/', admin.site.urls),
url(r'^accounts/', include('allauth.urls')),
]
You can also add the custom CSS yourself or my CSS (Well commented and documented but simple) that I have created during my use of the allauth templates. It includes styling for almost all the pages, and even mobile-friendly email templates for confirmation and password reset emails. You can do that by creating a static
folder in the project directory and placing the CSS in the folder accounts
.
Run python manage.py makemigrations
and python manage.py migrate
to make all the necessary migrations and run python manage.py runserver
to start the django server.
Follow the URL patterns to display the registration form.
Eg: Visit localhost:8000/accounts/login
to display the login page.
Basic Configuration
Most django-allauth
features are can be configured using the built-in adapters and variables by placing them in the file settings.py
. Although the documentation has tons of such options with good explanations, I have highlighted some important ones below.
Email confirmation expiry: Sets the number of days within which an account should be activated.
Eg: ACCOUNT_EMAIL_CONFIRMATION_EXPIRE_DAYS=7
Email required for activation: This option allows you to set whether the email address should be verified to register. Set False to disable email requirement.
Eg: ACCOUNT_EMAIL_REQUIRED = True
Account email verification: This option can be used to set whether an email verification is necessary for a user to log in after he registers an account. You can use ‘mandatory’ to block a user from logging in until the email gets verified. You can set options for sending the email but allowing the user to log in without an email. You can also set none to send no verification email. (Not Recommended)
Eg: ACCOUNT_EMAIL_VERIFICATION = "mandatory"
Login Attempt Limit: This is an important feature which can be used to prevent brute force attacks on the user login page on your website. The maximum number of login attempts can be set, and the user gets blocked from logging back in until a timeout. This feature makes use of ACCOUNT_LOGIN_ATTEMPTS_TIMEOUT
setting.
Eg: ACCOUNT_LOGIN_ATTEMPTS_LIMIT = 5
Login Attempt Limit timeout: This setting should be used with setting ACCOUNT_LOGIN_ATTEMPTS_LIMIT
. The value set is in seconds from the last unsuccessful login attempt. Please note that this does not protect admin login.
Eg: ACCOUNT_LOGIN_ATTEMPTS_TIMEOUT
= 86400 # 1 day in seconds
Login and Logout URL redirection: When user logs in or logs out, you might want to redirect the user to a particular URL or page and the below settings can be used to set that URL. By default, allauth redirects login to /accounts/profile/
URL and logout to the localhost:8000 or any localhost homepage.
Eg: ACCOUNT_LOGOUT_REDIRECT_URL ='/accounts/login/'
Eg: LOGIN_REDIRECT_URL = '/accounts/email/'
When you are done, your allauth settings should look similar to the below settings.
ACCOUNT_EMAIL_CONFIRMATION_EXPIRE_DAYS =1
ACCOUNT_EMAIL_REQUIRED = True
ACCOUNT_EMAIL_VERIFICATION = "mandatory"
ACCOUNT_LOGIN_ATTEMPTS_LIMIT = 5
ACCOUNT_LOGIN_ATTEMPTS_TIMEOUT = 86400 # 1 day in seconds
ACCOUNT_LOGOUT_REDIRECT_URL ='/accounts/login/'
LOGIN_REDIRECT_URL = '/accounts/email/' # default to /accounts/profile
Extending the django-alluth class and advanced customizations
This section deals with customizing django-allauth signup forms, intervening in registration flow to add custom process and validations of your own.
One of the most common queries about allauth is about adding additional fields or custom fields to the signup form. You can extend the SignupForm
class from allauth.account.forms
. All you need to do is create a custom class pass the SignupForm
to the custom class and define the custom fields and save it. It's vital to return the user object as it will be passed to other modules for validations. You also need to include variables ACCOUNT_FORMS
in settings.py
.
Let us see this using an example. In forms.py
.
from allauth.account.forms import SignupForm
from django import forms
class CustomSignupForm(SignupForm):
first_name = forms.CharField(max_length=30, label='First Name')
last_name = forms.CharField(max_length=30, label='Last Name')
def signup(self, request, user):
user.first_name = self.cleaned_data['first_name']
user.last_name = self.cleaned_data['last_name']
user.save()
return user
In the above snippet CustomSignupForm
is an extended class which inherits all the features of SignupForm
class and adds the necessary features. Here custom fields by the name first_name
and last_name
are created and saved in using the signup module in the same class.
The ACCOUNT_FORMS
in settings.py
for the above code is
ACCOUNT_FORMS = {
'signup': 'YourProject.forms.CustomSignupForm',
}
Any other custom forms created can be extended in ACCOUNT_FORMS
. The list is illustrated in the documentation.
Similarly, LoginForm
UserForm
AddEmailForm
and others can be extended. However, remember that when you extend these forms and link them in settings.py
. Do Not forget to pass the original form (For example SignupForm
) as a parameter to your class and sometimes you might have to handle custom validations and return user or some other value. Please refer to the source code to follow the correct flow.
User Intervention and Custom validations
I recently encountered some good questions on stack overflow and on the repository issue section with regards to adding custom validations and intervening in the user registration flow. When researching for a solution and scanning through the documentation, I found the DefaultAccountAdapter
very useful and indeed can be used to solve most of the customization problems that a user might encounter while using django-allauth
. I reproduce the answers and with some instructions below.
Example 1: Allow restricted list of email’s
After figuring out a way to store and fetch the restricted list, you can use the adapters and raise validation error in the registration form when a restricted email tries to register. Extend a DefaultAccountAdapter
and override the clean_email
method. Create an adapter.py
in your project directory and extend the default adapter class. You can also restrict the email providers (such as temporary email providers) from registering using Regular expressions. I will not cover identifying the email prover (user@provider.com
) as it is out of the scope of this article. But the flow remains the same.
from allauth.account.adapter import DefaultAccountAdapter
from django.forms import ValidationError
class RestrictEmailAdapter(DefaultAccountAdapter):
def clean_email(self,email):
RestrictedList = ['Your restricted list goes here.']
if email in RestrictedList
raise ValidationError('You are restricted from registering. Please contact admin.')
return email
Finally, point the account adapter in the settings.py
file to your extended class. ACCOUNT_ADAPTER = 'YourProject.adapter.RestrictEmailAdapter'
Example 2: Add a Maximum length to a username
As ACCOUNT_USERNAME_MAX_LENGTH
does not exist in the allauth library, DefaultAccountAdapter
can be used to achieve this feature without much pain. Extend the DefaultAccountAdapter
class and overriding the clean_username
method. You need to also reference the clean_username
once again after the custom validation to complete other inbuilt validations.
Note: The Last sentence in the above paragraph is the key to work with DefaultAccountAdapter
. You should never forget to reference the original module name for the module to complete other validations.
from allauth.account.adapter import DefaultAccountAdapter
from django.forms import ValidationError
class UsernameMaxAdapter(DefaultAccountAdapter):
def clean_username(self, username):
if len(username) > 'Your Max Size':
raise ValidationError('Please enter a username value less than the current one')
return DefaultAccountAdapter.clean_username(self,username) # For other default validations.
Finally, point to the subclass in your settings.py
ACCOUNT_ADAPTER = 'YourProject.adapter.UsernameMaxAdapter'
You can refer to the adapters.py
file in the source code and extend other modules and add a processor to change its flow. The modules such as populate_username
, clean_password
(which can be customized to restrict commonly used passwords) can have a custom process and flow without rewriting them.
DefaultAccountAdapter
can be a potent tool if used in the right circumstances to intervene in allauth's default process. allauth comes with a vast variety of inbuilt settings, and they can all be viewed here. You can also download the entire source code from the link in the references.
Setting up social login using django-allauth
Adding the necessary apps:
As illustrated in the allauth-documentation and in the previous section we need to add the necessary apps related to logins that we are going to be using. This section demonstrates the use of Google API configuration using allauth.socialaccount.providers.google
and Facebook API configuration using allauth.socialaccount.providers.facebook
. You need to add them to INSTALLED_APPS
.
After you do so, your installed apps should look like,
INSTALLED_APPS = [
'django.contrib.admin',
'allauth',
'allauth.account',
'allauth.socialaccount',
'allauth.socialaccount.providers.google',
'allauth.socialaccount.providers.facebook',
'django.contrib.auth',
'django.contrib.sites',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
]
Set SOCIALACCOUNT_QUERY_EMAIL=ACCOUNT_EMAIL_REQUIRED
, SOCIALACCOUNT_EMAIL_REQUIRED=ACCOUNT_EMAIL_REQUIRED
and SOCIALACCOUNT_STORE_TOKENS=False
.if required and you can read more about those settings here. We will also configure some settings for Facebook and Google under SOCIALACCOUNT_PROVIDERS
. On details about settings see the documentation here.
Your SOCIALACCOUNT_PROVIDERS
settings should look similar to,
SOCIALACCOUNT_PROVIDERS = {
'facebook': {
'METHOD': 'oauth2',
'SCOPE': ['email', 'public_profile', 'user_friends'],
'AUTH_PARAMS': {'auth_type': 'reauthenticate'},
'INIT_PARAMS': {'cookie': True},
'FIELDS': [
'id',
'email',
'name',
'first_name',
'last_name',
'verified',
'locale',
'timezone',
'link',
'gender',
'updated_time',
],
'EXCHANGE_TOKEN': True,
'LOCALE_FUNC': 'path.to.callable',
'VERIFIED_EMAIL': False,
'VERSION': 'v2.12',
},
'google': {
'SCOPE': [
'profile',
'email',
],
'AUTH_PARAMS': {
'access_type': 'online',
}
}
}
Run python manage.py make makemigrations
and python manage.py migrate
to create database entries. We can now create Facebook and Google API keys. I have briefly described the process below. I recommend you follow instructions on their respective official websites as their services and policies are subjected to change.
API Creation and Configuration:
Follow the below steps and seek out extra referees or tutorials on how to do this on the internet. A brief description is below.
Create a test app by visiting developers.facebook.com and filling in all the details.
Copy the App Id and Secret Key.
- Create Login API and copy the secret credentials.
- Don’t forget to place the correct callback URL while creating the API. Place
http://localhost:8000/accounts/google/login/callback/
in callback URL.
Admin Configuration
- Create a superuser(admin) by running
python manage.py createsuperuser
and fill out the details. - Go to
http://localhost:8000/admin
and log in to the admin console. - Go to the site and change
example.com
tohttp://localhost:8000
in both domain name and display name. - Now go to Social Applications and Add social applications and fill in the details.
- Repeat the same for Facebook and Google.
You are set and done. You can now go ahead and use Facebook and Google logins.
This is one of the first most comprehensive posts on dev.to. Feel free to send hugs or bugs my way.
Top comments (26)
Hi! Thanks for the obvious hard work you put into this. Tried working through it, and it wasn't working. Discovered that you need to add "SITE_ID =1" into your settings file and it all starts working.
Haven't gotten passed the initial setup, but looking forward to the rest!
I will fix it. Thanks.
why "SITE_ID =1" required?
Hi! How would I go about changing the way "Remember Me" checkbox is displayed?
I have tried this:
But it does not seem to work. I want to have a custom "Remember me" checkbox that nothing I do changes it
Great blog. It helped a lot setting user authentication in place.
One recommendation, I would encourage users to create a "user authentication" app within the DJANGO project in order to have a cleaner main folder. Just a thought.
It's a perfect tutorial so there is some points that not included in this tutorial witch is how to get the scope data from the social provider as example how to get it from discord so if you can update it this will be helpful
when I clik on Google login it redirects me to
and i want it to redirect me directly to provider login page
I don't know why facebook integration is not working on my live website, it's perfectly run on localhost but not on live website, can you please explain how to assign a user profile while we signup through facebook, I have 2 user types and I want to assign them one user profile can you please tell me how to do this :)
I recently got into a issue where user cannot login whose facebook id is made using mobile number and no email address is connected to it.
Is it due to that i kept ACCOUNT_EMAIL_REQUIRED = True ?
looking forward for solution.
Hey Gajesh, nice post!
Quick question: how can I exclude fields in my CustomSignUp view? Because, If I create my CustomSignUp adding some extra field (like 'role' or whatever), the username, email and password always are there.
Thanks!
How can i add custom phone number field in django allauth
Really nice in-depth tutorial. I was wondering if you've ever encountered a KeyError at /accounts/login/ 'BACKEND' issue and if so how did you resolve it? I've been trying to find a solution for over a week and just can't seem to resolve it.
Even posted a SOF question..
stackoverflow.com/questions/602517...
Has anyone had any success using it with DRF ?
this is great, but do you have a logical explanation why is the TEMPLATES setting is like this?
TEMPLATES = [
{
'BACKEND': 'django.template.backends.django.DjangoTemplates',
'DIRS': [
os.path.normpath(os.path.join(BASE_DIR, 'templates')),
],
'APP_DIRS': True,
'OPTIONS': {
'context_processors': [
'django.template.context_processors.debug',
'django.template.context_processors.request', => # "same as below"
'django.contrib.auth.context_processors.auth',
'django.contrib.messages.context_processors.messages',
'django.template.context_processors.request', => # "same as above"
],
},
},
]
is this necessary?
why not like this?
for it's more simple and understandable
============================================================
TEMPLATES = [
{
'BACKEND': 'django.template.backends.django.DjangoTemplates',
'DIRS': [
os.path.normpath(os.path.join(BASE_DIR, 'templates')),
],
'APP_DIRS': True,
'OPTIONS': {
'context_processors': [
'django.template.context_processors.debug',
'django.contrib.auth.context_processors.auth',
'django.template.context_processors.request', = > not "DRY"
'django.contrib.messages.context_processors.messages',
],
},
},
]
Is it possible to make the password field on the sign up page not required
one more correction : in the top section "allauthallauth.account" is mentioned which is actully "allauth.account".
Thanks for this deep tutorial