How to add authentication for users for django website using allauth and React
31.01.2025
33
0
0
0
1
Introduction
Yes, I haven't written about this site for a long time. And now I consider it my duty to finish it at any cost. So, we need to develop and add a system of authentication and registration of users to the site. How to do this, and what will it look like?
There is actually nothing complicated here. Think about it, we need to develop the following elements:
Login form
Registration form
Password change form
Logout form
Email confirmation form + template
Password reset form + template
Modal window for the user profile
And, actually, that's all... Although AllAuth does not necessarily need to be integrated into the site, you can implement registration and user management by yourself. It will still be easier. We will only have to implement the frontend part of the site.
I do not really want to overcomplicate and overload this article with the implementation of JWT tokens or the implementation of such user account management architectures as SAML2 or LDAP, or even registration through social networks. This will be in the following projects and articles because it has already turned out to be too big.
That is, in this article I will describe the process of integrating the AllAuth library on a django site with the minimum necessary functionality.
Writing a frontend for the login and registration forms
First, let's prepare the containers in which we will draw our modal windows. Add the following lines of code to the base.html template, right before the "main" tag and after the end of the block with the site header:
In my case, the tag with the data-type="profile" attribute will act as another button in the site header. It will open the user card. The user card will be rendered as a modal window, which will be located in the tag with id="auth-modal".
Now let's connect the new Auth component. This React component will draw modal windows for Login, Registration, the user card, and others. In the component file src/index.js, import:
The component file itself implements a component called Auth, which determines via props which modal window to show and how to contact the server, respectively. Surely, there is a simpler and more elegant way to do everything that I have just done, but I just need points of communication with the server from which I can get templates for login and registration, and it is changing the site accordingly. Here is the template file src/components/Auth.js:
Now about the structure and functionality of this module. There is the main exported module - Auth. This is actually a modal window that will contain a user card, a login form, registration forms, and other forms.
There are also two types of functions: on* and fetch*. The first communicates with the server, and the second updates the modal window. It is not necessary to follow this pattern, but it makes the code easier to maintain.
Then there are the updateEmail and updateSession functions. They do exactly what they say: update the email address information and update the current session information. I also added additional functions such as:
getCookie (name) - in case I want to get something and browser cookies.
getCSRFToken () - almost every request requires a CSRF token, so I wrote a separate function
As for the global URLs object. This is not the entire list of available paths to the allauth API, but the minimum required for us. Of course, you can delete it and write all the URLs manually, but that's without me. Moving on.
We must not forget to change the Header component in src/components/header.js. When creating buttons in the site header, I create custom events to which I will connect the modal window, like this:
Insert the highlighted lines of code
Connecting Allauth to the application
First, I would like to note the official documentation, it is complete and quite self-sufficient, although to understand how to use this library specifically on your site, you will need some time and study the official examples. Glory to them, it has some examples.
As always, let's start with installing the necessary packages. The django-allauth package is required, but django-allauth[socialaccount] is not, unless you need to use social networks as a provider for login.
Next, you need to add the following allauth backend to settings.py:
Allauth is designed as an embedded django application, or rather a whole bunch of applications that need to be connected:
It will also be necessary to connect and configure the email backend. For the sole purpose of testing confirmation of sent mail and the ability to reset the password. I will connect the test backend, because it is simply faster and more visual. All messages will be written to files. In the future, we will, of course, change it to a normal email backend.
Add these lines somewhere in settings.py
We are done in the settings.py file. All that remains is to add the paths and make migrations:
In fact, everything is ready, but not quite. I don't need to redirect to a separate page (this is not how my Django-React site will works). Ideally, I only need the API, and I will do the design myself. And to get access to the allauth API, I will need to tweak some more. Again, the official documentation is quite self-sufficient on this issue.
Add the these apps
Also you need to add a new paths to alluth API.
In the Website/urls.py file
This is not necessary, but still. Since the entire frontend is on React, I don't need extra pages either, which means my site will use allauth in "headless only" mode. To do this, add these lines somewhere in settings.py:
As you may have noticed, we have also added the HEADLESS_FRONTEND_URLS dictionary. It will be needed when we implement email confirmation and password reset, but for now, don't worry about it.
Connecting all together
From this point on, we can do the following: Stupidly write POST requests to the allauth API directly from React (we need literally 4 such requests: to log in /auth/login, to register /auth/signup, to confirm email /auth/email/verify, and to recover password /auth/password/request). In this case, no Django application will be required. Well, almost.
By the way, the entire headless API for making requests can be viewed here. I highly recommend it!!.
But you can do it differently: write a separate application, collect the necessary ModelForms there, render them on the server, and, if necessary, return them to the client. This is much longer but will allow you and me to better understand the internal workings of the allauth package, and moreover, this approach is more flexible in terms of design and fault tolerance of the application.
We will go the first way because React ... >﹏<
Making requests to server(Frontend)
User account page
We will start with the user card page. Of course, it will not be too big and complicated, rather the opposite. Minimum functionality, only necessary data. So far, without linking to other social networks.
First, we get the session status, i.e., we find out whether it is a guest or a registered user. Then, if it is a registered user, we display all the information that may be useful to him (mail, mail type, name). And of course, we add buttons for interaction.
Something like this, registered user
Something like this, not registered user
Each button was linked to a modal window update function. And further we will analyze how this window changes and how the request will be sent to the server.
Form and registration request
For user registration I use 4 fields (one of which is optional) (+1 hidden field, we fill this field with a csrf token). I also change the title and the main button of the modal window.
When you click the PROCEED button, the form is sent. Well, that's briefly, but if expanded, then ... First, the spinner opens, then we collect all the necessary data from the form and check them. We make a POST request to the server along the path /_allauth/browser/v1/auth/signup, i.e., URLs.SIGNUP, having previously left the CSRF token and the required response format in the request header. Then, regardless of the response, we close the form and leave a message to the user about the success of the request.
Form and login request
Login form, simpler than registration. It only requires a username and password.
We create three root elements and change the form itself, the button and the form title accordingly.
We send the form to the address /_allauth/browser/v1/auth/login, i.e. URLs.LOGIN.
Form and request to change password
To change the password we need a separate form. In the fetchPasswordChange function, we change the form, the title and the confirmation button. I also ask to enter the new password twice, just in case...
Before sending a request to change the password, you need to check whether the new passwords match each other. Then make a POST request to /_allauth/browser/v1/account/password/change or URLs.CHANGE_PASSWORD.
Form and password reset request
We update the modal window, i.e. the title, the form and the button itself, of course. To send a password recovery request, you only need to provide an email address.
So how does it work? The user has forgotten his password and wants to recover it. To do this, he sends a POST request to /_allauth/browser/v1/auth/password/request or URLs.REQUEST_PASSWORD_RESET. The server receives this request and sends an email to the specified address.
Password recovery request function
The message has been sent. The message will contain a link to a page with a key in the address. You need to follow this address to get to a page like this.
Out of the box, django-allauth does not provide a page for processing requests for password recovery or email verification (UNLESS, OF COURSE, THIS IS NOT HEADLESS MODE). Otherwise, there will be a redirect to a template page provided in normal mode.
On this page, you need to fill out this form. That is, enter a new password. It would probably be better if I also asked for password confirmation, but this will do. In fact, the form should be sent with two fields:
new password
generated key
In this case, I did not separate the on* and fetch* functions because this is a separate component and the component is quite small. Place this function in ./components/PasswordReset.js
In order for this function to make sense at all, I created a separate component called PasswordReset. I created a component file PasswordReset.js in components and connected it to index.js:
The full source code example of component:
That's not all. You will also need to create an html template on the server side and add the corresponding paths to urls.py
Form and request for email confirmation
My authentication system also supports email validation. There is no particular point in this for now, but in the future it will be quite useful if I, for example, want to know whether this is a valid email address or not.
We must send a PUT request to /_allauth/browser/v1/account/email or URLs.EMAIL
A letter with a link to the page with the key will be sent to the specified email. After going to this page, the user will see the following:
Where you only need to click on a button. Sending the confirmation form is done by this function:
In this case, I did not separate the on* and fetch* functions because this is a separate component and the component is quite small. Place this function in ./components/EmailVerify.js
It sends the key to the server to confirm the email and returns the corresponding message about the verification status.
Just like in the case of password reset, I created a separate component and connected it to index.js:
Here is a full source code of component, EmailVerify:
That's not all. You will also need to create an html template on the server side and add the appropriate paths to urls.py
Form and logout request
And finally, logout of the current session. A DELETE request is send to /_allauth/browser/v1/auth/session or URLs.LOGOUT. An error with code 401 will be returned, so we logout in the catch block.
Setting up routes and views for email verification and password reset
We are almost done. All that remains is to set up the Backend for email verification and password change. Create a new django application, if you don't know how, see here. Name it Authentication and of course connect it to the site project.
Next, create two templates in templates/Authentication, email_verify.html and password_reset.html
Contents of email_verify.html file:
Contents of password_reset.html file:
As you can see, they are almost identical. In principle, I could have made one common template, but I thought that perhaps, in the future, it might be necessary to somehow develop them separately. Now let's add two new urls to Authentication/urls.py:
Note that the paths match those I specified in settings.py earlier. All that remains is to create the corresponding views for these templates, email_verify and password_reset:
Everything is pretty straightforward here, we get the key from the URL, save it to the context when rendering and insert the key as the value of the data-key attribute in the containers. This attribute will then be used by React to send callbacks.
Conclusion
I have finished adding a system for authentication and registration of my guests on the site. Of course, you can also add login and registration via social networks or based on sent confirmation keys. All this will come later and perhaps in other projects, but definitely not in this article, it has already turned out to be too big.
You can download the current and full version of the project site here.
In the next article, we will work on translating our site into other languages, but for now, see you soon. ( ̄︶ ̄)↗