In this tutorial we will add an ability to sign up, sign in via Google, Deezer, and Spotify, view a success screen, and sign out afterward. Our project is going to be about music releases notifications.
I've already created a Django project with a landing page in a previous tutorial.
How will we do that?
We're going to use a social-app-django library. It supports a huge number of auth providers. They are also called "Backends" in the library. As you could guess, we will need Google, Deezer, and Spotify.
To install the library please follow an official installation guide.
Adding social-app-django to your Django project
First of all, you need to add the library to our INSTALLED_APPS
in your project's settings.py
INSTALLED_APPS = [
'django.contrib.admin',
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
# ...
'social_django',
# ...
'pages',
]
After that, migrate your database by running
python3 manage.py migrate
Then add social_django.urls
to your project's urls.py
urlpatterns = [
# ...
path('social/', include('social_django.urls')),
# ...
]
And SOCIAL_AUTH_URL_NAMESPACE
to your project's settings.py
again
SOCIAL_AUTH_URL_NAMESPACE = 'social'
Now you should have nothing, but we're ready to add an auth provider to the project. For more information, you can read the official python-social-auth installation guide for Django.
Authentication via Google(+)
First, you need to get credentials for the application
- Visit Google API Console
- Go to credentials
- Create credentials
- Add
http://127.0.0.1:8000/social/complete/google-plus/
to Authorized redirect URIs - Here you'll have to add your production redirect URL once you have one
Now you should see Client ID and Client secret in your app. Add them to project's settings.py
SOCIAL_AUTH_GOOGLE_PLUS_KEY = 'Your Client ID'
SOCIAL_AUTH_GOOGLE_PLUS_SECRET = 'Your Client secret'
Add Google to AUTHENTICATION_BACKENDS
in project's settings.py
AUTHENTICATION_BACKENDS = (
'social_core.backends.google.GooglePlusAuth',
)
And finally, add a link to sign in via Google to your menu or header or wherever you want your users to click to sign in
<a href="{% url "social:begin" "google-plus" %}">Google</a>
For more reading about how authentication via Google works here's the official guide.
Authentication via Deezer
The process for Deezer authentication is pretty similar to Google's one. First, getting credentials
- Visit Deezer for developers
- Create an app
- Set
http://127.0.0.1:8000/social/complete/deezer/
to Redirect URL after authentication - And again, here you'll have to add your production redirect URL once you have one
Now you should see Application id and a Secret Key in your app. Add them to project's settings.py
SOCIAL_AUTH_DEEZER_KEY = 'Your Application id'
SOCIAL_AUTH_DEEZER_SECRET = 'Your Secret Key'
Again, add Deezer to AUTHENTICATION_BACKENDS
in project's settings.py
AUTHENTICATION_BACKENDS = (
'social_core.backends.google.GooglePlusAuth',
'social_core.backends.deezer.DeezerOAuth2',
)
And again, a link to sign in via Deezer
<a href="{% url "social:begin" "deezer" %}">Deezer</a>
One more thing
You might want to ask for some permissions. For example, Deezer does not provide user's email by default. You need to ask a permission for email
. You can check out a full list of available permissions in official permissions documentation.
Adding required permissions is pretty simple with the social-app-django
library. You just need to add permission you want to a scope
constant in the project's settings.py
. The constant, in Deezer case, has to be called SOCIAL_AUTH_DEEZER_SCOPE
SOCIAL_AUTH_DEEZER_SCOPE = ['basic_access', 'email']
Authentication via Spotify
Spotify authentication is as similar to Google as Deezer is.
- Visit Spotify for developers
- Create a Client ID
- Set
http://127.0.0.1:8000/social/complete/spotify/
to Redirect URIs - And again, here you'll have to add your production redirect URL once you have one
Now you should see Client ID and a Client Secret in your app. Add them to project's settings.py
SOCIAL_AUTH_SPOTIFY_KEY = 'Your Client ID'
SOCIAL_AUTH_SPOTIFY_SECRET = 'Your Client Secret'
Again, add Spotify to AUTHENTICATION_BACKENDS
in project's settings.py
AUTHENTICATION_BACKENDS = (
'social_core.backends.google.GooglePlusAuth',
'social_core.backends.deezer.DeezerOAuth2',
'social_core.backends.spotify.SpotifyOAuth2',
)
And again, a link to sign in via Spotify
<a href="{% url "social:begin" "spotify" %}">Spotify</a>
Regarding permissions, I need user-read-email
and user-library-read
. You can check out a full list of available permissions in official permissions documentation.
SOCIAL_AUTH_SPOTIFY_SCOPE = ['user-read-email', 'user-library-read']
Life after sign in
Usually, after a sign in it's a good idea to show some sort of dashboard or feed or whatever is the main purpose of your application. I'm going to show a screen with all the latest music releases.
First, let's create a releases
app
python3 manage.py startapp releases
Add the app to installed apps in the project's settings.py
INSTALLED_APPS = [
'django.contrib.admin',
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
'social_django',
'pages',
'releases',
]
Add URLs to the project's URLs in the project's urls.py
urlpatterns = [
# ...
path('', include('releases.urls')),
# ...
]
Define a /releases
URL in releases/urls.py
from django.urls import path
from . import views
urlpatterns = [
path('releases', views.index, name='index'),
]
Create a view in releases/views.py
def index(request):
return render(request, 'releases/index.html')
Create a simple template to show that we care about our users in releases/templates/releases/index.html
(I hate to have to write releases
two times too)
<h1>Latest Releases</h1>
<p>We care about you, but we don't have anything done yet.</p>
Now that we have somewhere to redirect a user after a sign in, there is only one thing left to do — set a LOGIN_REDIRECT_URL
in the project's settings.py
LOGIN_REDIRECT_URL = '/releases'
After this line is added all users should go directly to /releases
URL after they sign in.
Fixing duplicate users
Now that we have the ability to sign in with a couple different accounts there is one problem — we don't do anything with duplicate users, users that have identical email. We can quickly check that by signing up 2 times via two different services (with Google and Spotify for example).
Then we can check that there are 2 users by running a Django shell
python3 manage.py shell
And checking current count of users there
from django.contrib.auth.models import User
User.objects.count()
We can also investigate what is the difference between them
vars(User.objects.all())
To fix this problem we'll have to learn a bit more how social-app-django
works.
When a user signs in they go through a so-called pipeline. Here's how the default pipeline looks like
(
# Get the information we can about the user and return it in a simple
# format to create the user instance later. On some cases the details are
# already part of the auth response from the provider, but sometimes this
# could hit a provider API.
'social_core.pipeline.social_auth.social_details',
# Get the social uid from whichever service we're authing thru. The uid is
# the unique identifier of the given user in the provider.
'social_core.pipeline.social_auth.social_uid',
# Verifies that the current auth process is valid within the current
# project, this is where emails and domains whitelists are applied (if
# defined).
'social_core.pipeline.social_auth.auth_allowed',
# Checks if the current social-account is already associated in the site.
'social_core.pipeline.social_auth.social_user',
# Make up a username for this person, appends a random string at the end if
# there's any collision.
'social_core.pipeline.user.get_username',
# Send a validation email to the user to verify its email address.
# Disabled by default.
# 'social_core.pipeline.mail.mail_validation',
# Associates the current social details with another user account with
# a similar email address. Disabled by default.
# 'social_core.pipeline.social_auth.associate_by_email',
# Create a user account if we haven't found one yet.
'social_core.pipeline.user.create_user',
# Create the record that associates the social account with the user.
'social_core.pipeline.social_auth.associate_user',
# Populate the extra_data field in the social record with the values
# specified by settings (and the default ones like access_token, etc).
'social_core.pipeline.social_auth.load_extra_data',
# Update the user record with any changed info from the auth service.
'social_core.pipeline.user.user_details',
)
If you like to, you can read a description for each stage of the pipeline. But what interests us at the moment is the 7th step, social_core.pipeline.social_auth.associate_by_email
which is disabled by default. What it does is it
Associates the current social details with another user account with a similar email address
Sounds like exactly what we need. Just uncomment the line with this setting and copy the pipeline to your project's settings.py
SOCIAL_AUTH_PIPELINE = (
'social_core.pipeline.social_auth.social_details',
'social_core.pipeline.social_auth.social_uid',
'social_core.pipeline.social_auth.auth_allowed',
'social_core.pipeline.social_auth.social_user',
'social_core.pipeline.social_auth.associate_by_email',
'social_core.pipeline.user.create_user',
'social_core.pipeline.social_auth.associate_user',
'social_core.pipeline.social_auth.load_extra_data',
'social_core.pipeline.user.user_details',
)
You can read more about in the official docs for pipelines. We'll build a custom pipeline in the next part of the series.
Signing out
You might want to add an ability for your users to sign out. I would not recommend doing that since this is just another opportunity for a user to leave your site but In case you still want to add it, it's pretty easy.
Django has an already built-in support for authentication called django.contrib.auth
. Right now, we'll need just the sign-out part of it.
First, add django.contrib.auth.urls
to your project's urls.py
urlpatterns = [
# ...
path('', include('django.contrib.auth.urls')),
# ...
]
Then, set LOGOUT_REDIRECT_URL
to '/'
in your project's settings.py
so that users are redirected to the homepage after they sign out
LOGOUT_REDIRECT_URL = '/'
Now, all that is left is to add a sign-out link wherever you want
<a href="{% url 'logout' %}" class="header-link">Log out</a>
Showing only relevant links
But right now your user can see all sign in links as well as a sign-out link. You probably wouldn't want a user to sign in or out 2 times and what does that even mean? So let's show only relevant links.
Django's user model has a special attribute for that called is_authenticated
that we can use. We can just use a simple if
in our template and check if a user
, a variable which is already available in our templates, is_authenticated
.
{% if user.is_authenticated %}
<a href="/logout">Log out</a>
{% else %}
<a href="{% url "social:begin" "google-plus" %}">Google</a>
<a href="{% url "social:begin" "deezer" %}">Deezer</a>
<a href="{% url "social:begin" "spotify" %}">Spotify</a>
{% endif %}
Conclusion
In this story I’ve covered:
- how to use a
social-app-django
library - how to create apps, set custom scopes in Google, Deezer, and Spotify and of course integrate those services into your application
- how to create a simple success page to show after the sign in
- what is a pipeline in
social-app-django
library - and how to sign users out
This is the second part of the series of articles about the MuN. Stay tuned for part 3. You can find the code of this project, as well as my other projects, on my GitHub page. Leave your comments down below and follow me if you liked this article.
Top comments (1)
Hi, thanks for the awesome article. I am trying to use Facebook to my django app. So i finally managed to create a successful login and account created. Now there is a case that i should handle which is when facebook user does not have an email address. What should i do in this case?