Django authentication with Twitter

Because OAuth 2 has emerged as the industry standard for social applications and third-party authentication. As a result, you may concentrate on learning and implementing it to support many social authentication providers. The standard OAuth 2 providers include Facebook, Google, GitHub and, Twitter.

Authentication is the activity of establishing whether someone or something is, indeed, what it claims to be.

In a general perspective, the authentication system checks if the user credentials provided during login match the respective values stored in the application’s record – mostly the database for the given user attempting to login to the application. In addition, the password is referred to as an authentication factor, and it should be known by the user trying to log in alone.

Django authentication with Twitter

As of this writing, there are numerous kinds of authentication. For instance, Multifactor authentication(MFA) or two-factor authentication. In the previous case, the user can provide a unique RSA key on top of their password. Others can even use their iris or fingerprints.

How does Django Perform authentication?

Django comes with a user authentication system that allows administering and managing user and group permissions and cookie-based sessions.

This system addresses both authentication and authorization, where the latter permits an authenticated user to perform certain tasks and access specific data within your application.

Through Django authentication, parameters are automatically set up when you create your Django project using the following command.

django-admin startproject

The user object is the heart of the Django authentication system. It’s through the User object that access is managed to your site. This user object has attributes such as, “email”, “username”, “is_active”, “last_login”, and “password”. It also has methods like has_perm(), get_username(), check_password().

Anytime you make permission changes in Django, the following command must be run to propagate those changes to the database.

python3 manage.py migrate 

The basic syntax to see if a user has permissions to the data of a given application would be:

user.has_perm(“my_app.view_my_model”)

Users get logged in through the login() function and logged out through the logout() function. Further, Django supplies mechanisms to require a user to be logged in, such as the @login_required decorator.

In the case of password management, Django, by default, uses a PBKDF2(cryptographic key derivation functions) algorithm with a SHA256 hash, a password stretching mechanism recommended by NIST. However, it is usually sufficient for most users since it’s very secure and needs a lot of computing time to break. In addition, you can use bcrypt and Argon2 with Django by installing their libraries using pip.

You may also consider using Django password validators to ensure sufficiently strong passwords are used – these kinds of settings are made in the settings.py file under the section AUTH_PASSWORD_VALIDATORS.

The OAuth 2 process

OAuth 2 was created to be a web authentication protocol. It isn’t the same as a network authentication protocol because it presumes you have HTML rendering and browser redirection capabilities.

It is a disadvantage for a JSON-based API, but we always come up with workarounds. The steps in this article assume you are developing a standard server-side website.

The OAuth 2 Flow on the Server

The first phase takes place entirely outside of the application flow. In this step, the project owner will register each OAuth 2 provider for which you require logins.

They will supply the OAuth 2 provider with a callback URI during this registration, where their application will be ready to receive requests. As a result, they get a client key and a client secret in exchange.

These tokens are used to confirm login requests throughout the authentication procedure.

The flow starts when your application generates a page with a button like “Log in with Facebook” or “Sign in with Google.”
In essence, these are nothing more than simple links, each of which goes to a URL similar to this:

https://oauth2provider.com/auth?response_type=code&client_id=CLIENT_KEY&redirect_uri=CALLBACK_URI&scope=profile&scope=email

In the above case, you have submitted the client key and redirect URI, but no secrets are shared.

In exchange, you’ve requested an authentication code and access to both the ‘profile’ and ’email’ scopes from the server. These scopes specify the permissions you ask for from the user and limit the access token’s authorization.

After receiving the access token, the user’s browser is redirected to a dynamic page controlled by the OAuth 2 provider.
Before proceeding, the OAuth 2 provider double-checks that the callback URI and client key are the same. If they do, depending on the user’s session tokens, the flow briefly diverges.

The user will be prompted to log in if they are not already logged in to that service.

The user is then provided with a window asking for permission to allow your program to log in after they’ve logged in.

If the user gives the necessary permissions, the OAuth 2 server forwards them to the callback URI they had specified earlier, with an authorization code included in the query parameters as follows:

GET https://api.yourapp.com/oauth2/callback/?code=AUTH_CODE

The authorization code is a one-time-use token that expires quickly; thus, as soon as you receive it, your server should issue a new request to the OAuth 2 provider, including both the authorization code and your client secret as shown below:

OST https://oauth2provider.com/token/?
grant_type=authorization_code&
code=AUTH_CODE&
redirect_uri=CALLBACK_URI&
client_id=CLIENT_KEY&
client_secret=CLIENT_SECRET

The objective of this authorization code is to authenticate the POST request above, but it must be routed through the user’s system owing to the nature of the flow. As a result, it is inherently risky.

The authorization code’s limitations, i.e., it expires rapidly and can only be used once, are in place to reduce the risk of sending an authentication credential through an untrusted system.

The main component of the OAuth 2 server-side login process is this call, which is made directly from your server to the OAuth 2 provider’s server.

Controlling the call ensures that it is TLS-secured, making it more resistant to wiretapping attacks.

The authorization code guarantees that the user gave explicit consent. Further, the client secret, which is never visible to your users, ensures that this request isn’t the result of a virus or spyware intercepting the authorization code on the user’s system.

If everything checks out, the server will return an access token, which you can use to make calls to that provider while logged in as the user.

Your server then redirects the user’s browser to the landing page for users who have just logged in after receiving the access token from the server to continue their original intent of accessing the given site.

The access token is frequently stored in the user’s server-side session cache. As a result, the server can still make calls to the registered OAuth 2 provider when needed.

Google, for example, contains a refresh token that extends the duration of your access token, while Facebook has an endpoint where you can exchange short-lived access tokens for longer-lived ones.

For a REST API, this flow is inconvenient. While you could have the front-end client build the initial login page and the backend supplies a callback URL, you’ll run into problems eventually.

Once you’ve got the access token, you want to send the visitor to the landing page, but there’s no clear, RESTful way to do so.

Creating a Django Application

Creating Django Application(TwitterLogin)

We will start by creating a virtual environment and installing Django.

Step 1: mkdir django-twitter-auth && cd django-twitter-auth

Step 2: virtualenv twitter_env

Create a virtual environment
Create a virtual environment

Step 3: source twitter_env/bin/activate

source twitter_env/bin/activate
source twitter_env/bin/activate

Step 4: pip install Django==3.2.6

Install Django using pip
Install Django using pip

At this point, we will now create a new app then apply the migrations. Finally, we will run the server.

Step 5: django-admin startproject TwitterLogin_app

Step 6: python manage.py migrate

python manage.py migrate
python manage.py migrate


Step 7: python manage.py runserver

python manage.py runserver
python manage.py runserver

When you access the URL http://127.0.0.1:8000, the following screen should be visible.

default Django page after installation
default Django page after installation

Django Allauth configuration

The next step is to set up Django Allauth for our Codelogin application. To do so, let’s install Django-allauth using pip as follows.

pip install django-allauth==0.45.0
install django-allauth using pip

We will then modify the INSTALLED_APPS in the settings.py by adding allauth apps. If we do not do this, Django Allauth will not work with our TwitterLogin_app. The new changes should appear as follows.

# TwitterLogin_app/settings.py

INSTALLED_APPS = [
"django.contrib.admin",
"django.contrib.auth",
"django.contrib.contenttypes",
"django.contrib.sessions",
"django.contrib.messages",
"django.contrib.staticfiles",
"django.contrib.sites",
# allauth apps
"allauth", # new
"allauth.account", # new
"allauth.socialaccount", # new
# twitter
"allauth.socialaccount.providers.twitter", # new
]

Initially, we added the Django “sites” framework to enable Allauth to work as expected. Then we added the primary Allauth apps that comprise allauth, allauth.account, and allauth.socialaccount.

After that, we will add the following set of code at the bottom of the settings.py

# TwitterLogin_app/settings.py

AUTHENTICATION_BACKENDS = (
"allauth.account.auth_backends.AuthenticationBackend",
)

SITE_ID = 1
ACCOUNT_EMAIL_VERIFICATION = "none"
LOGIN_REDIRECT_URL = "home"
ACCOUNT_LOGOUT_ON_GET = True

The above section defines several parameters that we will explain below.

Allauth defines the authentication backend that ensures that all the login and logout through the regular username and password or OAuth is now handled by Allauth.

ACCOUNT_EMAIL_VERIFICATION =” none” is responsible for turning off email verification because it is unnecessary now. It is because Django does a workflow setup for its email verification.

LOGIN_REDIRECT_URL=” home” is responsible for directing the user to the homepage after successful authentication.

ACCOUNT_LOGOUT_ON_GET=True ensures that the confirm logout page is skipped by directly logging out the user when the logout button is clicked through a GET request.

SITE_ID – is needed for Django Allauth to work correctly.

Make the following updates to urls.py

from django.contrib import admin
from django.urls import path, include # new

urlpatterns = [
path("admin/", admin.site.urls),
path("accounts/", include("allauth.urls")), # new
]

That will include Django Allauth. In addition, we need to apply the migrations associated with Django Allauth by running the following command.

python manage.py migrate

Ensure not to forget the above step because Django Allauth needs the new tables.

Create Templates for TwitterLogin Application

In this section, we will create templates for our application to help communicate the process happening in the application.
First, we will create a “templates” directory in the base directory and two other files, namely, home.html and base.html.

mkdir templates && cd templates

touch home.html base.html

We will then update the path of the template on the settings.py to make it easier for Django to find the templates. The new changes should appear as follows.

# TwitterLogin_app/settings.py

TEMPLATES = [
{
…
"DIRS": [str(BASE_DIR.joinpath("templates"))],
…
},
]

Then also make the following changes to the two template files as follows.

<!-- templates/base.html-->

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <link
      href="https://cdn.jsdelivr.net/npm/bootstrap@5.0.0-beta1/dist/css/bootstrap.min.css"
      rel="stylesheet"
    />
    <link
      rel="stylesheet"
      href="https://stackpath.bootstrapcdn.com/font-awesome/4.7.0/css/font-awesome.min.css"
    />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Django Twitter Login</title>
  </head>
  <body>
    {%% block content %%} {%% endblock content %%}
  </body>
</html>
<!-- templates/home.html -->

{%% extends '_base.html' %%} {%% load socialaccount %%}

{%% block content %%}

<div class="container" style="text-align: center; padding-top: 10%%;">
  <h1>Django Twitter Login</h1>

  <br /><br />

  {%% if user.is_authenticated %%}
    <h3>Welcome {{ user.username }} !!!</h3>
    <br /><br />
    <a href="{%% url 'account_logout' %%}" class="btn btn-danger">Logout</a>
  {%% endif %%}
</div>

{%% endblock content %%}

Next, we will create a view to serve the templates we have created above. Inside the view.py file, add the following code.

# TwitterLogin_app/views.py

from django.views.generic import TemplateView

class Home(TemplateView):
  template_name = "home.html"


We will then create a new URL so that the final look of the urls.py is shown below.

# TwitterLogin_app/urls.py

from django.contrib import admin
from django.urls import path, include


from .views import Home # new

urlpatterns = [
path("admin/", admin.site.urls),
path("accounts/", include("allauth.urls")),
path("", Home.as_view(), name="home"), # new
]

Creating superuser credentials

To create a superuser for our DjangoTwitter application, we will run the following command and pass in the required details, including the username, email address, a designated password, and a confirmation.

$ python manage.py createsuperuser
create superuser for DjangoTwitterLogin
create superuser for DjangoTwitterLogin

We are not done with setting up the Django Allauth and doing the configurations as well. Now, we are super ready to test. You should be able to run the application and log in using a username and a password. In our case, we will use the credentials we created in the section above while examining superuser credentials. To access the login page, you can access the following link, http://127.0.0.1:8000/accounts/login/

Note that you can also make changes to the CSS stylesheets to make your application more appealing to the user. In addition, you may also choose to make changes to the default templates.

Setting Up Twitter OAuth 2 Provider

Setting up Twitter is not different from other social sites like Facebook, Github, and Google. The steps are as follows:

  • Creation of an OAuth 2 app on your developer Twitter account
  • Register the OAuth 2 provider on your Django admin page.
  • Update templates/home.html accordingly.

The first step is to apply for a Twitter developer account. During the application process, you will be prompted to answer several questions to qualify you and make better recommendations on which services to use. For instance, in our case, we are only interested in third-party authentication of apps via Twitter.

applying for a developer account

So, it would help if you navigated to the Projects and Apps section after completing the account application process. In this section, use the button “Create App” to specify the name of your application and provide other details.

create an app and give it the name DjangoTwitterLogin
create an app and give it the name DjangoTwitterLogin

Give a name for the app and write down the API key and API secret key.

take note of the keys and tokens
take note of the keys and tokens


Then enable “Enable 3-legged OAuth” and “Request email address from users” under “Authentication Settings.”
Also include the URLs for the callback, website, terms of service, and privacy policy.

authentication settings

Go to http://127.0.0.1:8000/admin and log in.

First, we will add a new site with the domain name 127.0.0.1 and the display name 127.0.0.1. Below is the completed sample we used.

Then click “Add Social Application” under “Social Applications” and enter the necessary details as indicated below.

Add Twitter as a new social application
Add Twitter as a new social application

Select Twitter as your provider. Then, give it a name like DjangoTwitterLogin in our case.

Add the API key (to Client id) and API secret key (to Secret key) that you noted earlier on to the Secret key.

One of the Chosen Sites should be example.com, http://127.0.0.1:8000. When you are done, then make the following updates to templates/home.html

{%% extends 'base.html' %%} {%% load socialaccount %%}

{%% block content %%}

<div class="container" style="text-align: center; padding-top: 10%%;">
  <h1>Django Social Login</h1>

  <br /><br />

  {%% if user.is_authenticated %%}
    <h3>Welcome {{ user.username }} !!!</h3>
    <br /><br />
    <a href="{%% url 'account_logout' %%}" class="btn btn-danger">Logout</a>
  {%% else %%}

    ...

    <!-- Twitter button starts here -->
      </a>
      <a href="{%% provider_login_url 'twitter' %%}" class="btn btn-primary">
        <i class="fa fa-twitter fa-fw"></i>
        <span>Login with Twitter</span>
      </a>
    <!-- Twitter button ends here -->
  {%% endif %%}
</div>

{%% endblock content %%}

Access HTTP://127.0.0.1/accounts/login to access the login page, which should appear as follows.

Sign-in Page

After clicking on Twitter, you will be taken to the following interface that will prompt you to authorize DjangoTwitterLogin to access your Twitter account.

Authorize DjangoTwitterLogin to access your account
Authorize DjangoTwitterLogin to access your account

When you provide the correct credentials, you will be directed to the DjangoTwitterLogin home page that will look like this one here.

Successfully logged in with Twitter
Successfully logged in with Twitter

Complete source code for the important sections.

# TwitterLogin_app/settings.py

"""
Django settings for TwitterLogin_app project.

Generated by 'django-admin startproject' using Django 3.2.6.

For more information on this file, see
https://docs.djangoproject.com/en/3.2/topics/settings/

For the full list of settings and their values, see
https://docs.djangoproject.com/en/3.2/ref/settings/
"""

from pathlib import Path

# Build paths inside the project like this: BASE_DIR / 'subdir'.
BASE_DIR = Path(__file__).resolve().parent.parent


# Quick-start development settings - unsuitable for production
# See https://docs.djangoproject.com/en/3.2/howto/deployment/checklist/

# SECURITY WARNING: keep the secret key used in production secret!
SECRET_KEY = 'django-insecure-an%%-hg13+tpii+1!_$_$4-_va4r!@15fb&-+&h+w^js7cq9-+8'

# SECURITY WARNING: don't run with debug turned on in production!
DEBUG = True

ALLOWED_HOSTS = ['*']


# Application definition

INSTALLED_APPS = [
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',

    "django.contrib.sites", 
    # allauth apps
    "allauth", # new
    "allauth.account", # new
    "allauth.socialaccount", # new
    
    # twitter
    "allauth.socialaccount.providers.twitter", # new
]

MIDDLEWARE = [
    'django.middleware.security.SecurityMiddleware',
    'django.contrib.sessions.middleware.SessionMiddleware',
    'django.middleware.common.CommonMiddleware',
    'django.middleware.csrf.CsrfViewMiddleware',
    'django.contrib.auth.middleware.AuthenticationMiddleware',
    'django.contrib.messages.middleware.MessageMiddleware',
    'django.middleware.clickjacking.XFrameOptionsMiddleware',
]

ROOT_URLCONF = 'TwitterLogin_app.urls'

TEMPLATES = [
    {
        'BACKEND': 'django.template.backends.django.DjangoTemplates',
        'DIRS': [str(BASE_DIR.joinpath("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',
            ],
        },
    },
]

WSGI_APPLICATION = 'TwitterLogin_app.wsgi.application'


# Database
# https://docs.djangoproject.com/en/3.2/ref/settings/#databases

DATABASES = {
    'default': {
        'ENGINE': 'django.db.backends.sqlite3',
        'NAME': BASE_DIR / 'db.sqlite3',
    }
}


# Password validation
# https://docs.djangoproject.com/en/3.2/ref/settings/#auth-password-validators

AUTH_PASSWORD_VALIDATORS = [
    {
        'NAME': 'django.contrib.auth.password_validation.UserAttributeSimilarityValidator',
    },
    {
        'NAME': 'django.contrib.auth.password_validation.MinimumLengthValidator',
    },
    {
        'NAME': 'django.contrib.auth.password_validation.CommonPasswordValidator',
    },
    {
        'NAME': 'django.contrib.auth.password_validation.NumericPasswordValidator',
    },
]


# Internationalization
# https://docs.djangoproject.com/en/3.2/topics/i18n/

LANGUAGE_CODE = 'en-us'

TIME_ZONE = 'UTC'

USE_I18N = True

USE_L10N = True

USE_TZ = True


# Static files (CSS, JavaScript, Images)
# https://docs.djangoproject.com/en/3.2/howto/static-files/

STATIC_URL = '/static/'

# Default primary key field type
# https://docs.djangoproject.com/en/3.2/ref/settings/#default-auto-field

DEFAULT_AUTO_FIELD = 'django.db.models.BigAutoField'

AUTHENTICATION_BACKENDS = (
    "allauth.account.auth_backends.AuthenticationBackend",
)

SITE_ID = 1
ACCOUNT_EMAIL_VERIFICATION = "none"
LOGIN_REDIRECT_URL = "home"
ACCOUNT_LOGOUT_ON_GET = True

<!-- base.html-->

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <link
      href="https://cdn.jsdelivr.net/npm/bootstrap@5.0.0-beta1/dist/css/bootstrap.min.css"
      rel="stylesheet"
    />
    <link
      rel="stylesheet"
      href="https://stackpath.bootstrapcdn.com/font-awesome/4.7.0/css/font-awesome.min.css"
    />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Django Twitter Login</title>
  </head>
  <body>
    {%% block content %%} {%% endblock content %%}
  </body>
</html>
<!-- home.html-->

{%% extends 'base.html' %%} {%% load socialaccount %%}

{%% block content %%}

<div class="container" style="text-align: center; padding-top: 10%%;">
  <h1>Django Twitter Login</h1>

  <br /><br />

  {%% if user.is_authenticated %%}
    <h3>Welcome {{ user.username }} !!!</h3>
    <br /><br />
    <a href="{%% url 'account_logout' %%}" class="btn btn-danger">Logout</a>
  {%% endif %%}
</div>

{%% endblock content %%}

# TwitterLogin_app/views.py

from django.views.generic import TemplateView


class Home(TemplateView):
    template_name = "home.html"
# TwitterLogin_app/urls.py

from django.contrib import admin
from django.urls import path, include

from .views import Home # new


urlpatterns = [
    path("admin/", admin.site.urls),
    path("accounts/", include("allauth.urls")),
    path("", Home.as_view(), name="home"), # new
]

Conclusion

This article covered all you need to know about using Twitter as your OAuth 2 provider. We also covered in detail how OAuth 2 works, including the entire flow. Further, we created a Django application step by step, verifying that it works as expected at each level.

Finally, we walked over to apply for a Twitter developer account, created an OAuth 2 app, and generated the access key and tokens needed to facilitate login on our application using Twitter.

We hope this article has been informative enough to psyche you to use OAuth 2 with Twitter in your upcoming applications.

Similar Posts

Leave a Reply

Your email address will not be published. Required fields are marked *