Simple Google Authentication in Django.

This is my first post on medium.com, so I thought of sharing some cool stuffs which I do with my new love, Django. :-P

I would be writing on how to build a simple google authentication app on Django framework.

Step 1: Create a folder 
$ mkdir login
Step 2: Install virtual environment
$ virtualenv env -p python3
Step 3: Install Djanog= 1.11 and Django-admin
$ pip install django
$ pip install django-admin
Step 4: Start Django project
$ django-admin startproject login
$ cd login
Step 5: Start Django app
$ python manage.py startapp home
Folder tree should look like this.
For social authentication you have to install python social authentication package
$ pip install social-auth-app-django
$ pip install psycopg2

Now open setting.py of login folder in text editor.
Add ‘home’ and ‘social_django’ inside INSTALLED_APPS

INSTALLED_APPS = [
....
‘django.contrib.staticfiles’,
‘home’,
‘social_django’,
]
#Some other dependencies
AUTHENTICATION_BACKENDS = (
‘social_core.backends.open_id.OpenIdAuth’,
‘social_core.backends.google.GoogleOpenId’,
‘social_core.backends.google.GoogleOAuth2’,
‘django.contrib.auth.backends.ModelBackend’,
)
SOCIAL_AUTH_URL_NAMESPACE = ‘social’
'context_processors': [
...
'social_django.context_processors.backends',
'social_django.context_processors.login_redirect',
],
SOCIAL_AUTH_PIPELINE = (
'social.pipeline.social_auth.social_details',
'social.pipeline.social_auth.social_uid',
'social.pipeline.social_auth.auth_allowed',
'social.pipeline.social_auth.social_user',
'social.pipeline.user.get_username',
'social.pipeline.user.create_user',
'social.pipeline.social_auth.associate_user',
'social.pipeline.debug.debug',
'social.pipeline.social_auth.load_extra_data',
'social.pipeline.user.user_details',
'social.pipeline.debug.debug',
)

SOCIAL_AUTH_GOOGLE_OAUTH2_IGNORE_DEFAULT_SCOPE = True
SOCIAL_AUTH_GOOGLE_OAUTH2_SCOPE = [
'https://www.googleapis.com/auth/userinfo.email',
'https://www.googleapis.com/auth/userinfo.profile'
]
# Google+ SignIn (google-plus)
SOCIAL_AUTH_GOOGLE_PLUS_IGNORE_DEFAULT_SCOPE = True
SOCIAL_AUTH_GOOGLE_PLUS_SCOPE = [
'https://www.googleapis.com/auth/plus.login',
'https://www.googleapis.com/auth/userinfo.email',
'https://www.googleapis.com/auth/userinfo.profile'
]
LOGIN_URL = '/account/login/'

After this most important part comes that Google auth key and secret key.

To create an API key:

  1. Go to the Google Developers Console
  2. Create a project and fill in all the details
  3. On the right side there is credentials tab, select it .
  4. Click on Create Credentials then Oauth Client ID. Select application type Webapp , Give any name of your choice.
    Under Authorized JavaScript origins fill
    http://localhost:8000
    Authorized redirect URIs
    http://localhost:8000/account/complete/google-oauth2/
6. Copy the CLient ID and Client Secret
Under setting.py
SOCIAL_AUTH_GOOGLE_OAUTH2_KEY ='' #Paste CLient Key
SOCIAL_AUTH_GOOGLE_OAUTH2_SECRET = '' #Paste Secret Key

Open url.py under login and write the following code.

from django.conf.urls import include, url
from django.contrib import admin
from django.conf import settings
from django.conf.urls.static import static
urlpatterns = [
url(r'^', include('home.urls')),
url(r'^account/', include('social_django.urls', namespace='social')),
url(r'^account/', include('django.contrib.auth.urls', namespace='auth')),
url(r'^admin/', include(admin.site.urls)),
]

Open models.py under home folder and write the following code.

from django.db import models
from django.contrib.auth.models import User
from django.db.models.signals import post_save
from django.dispatch import receiver
class Profile(models.Model):
user = models.OneToOneField(User,unique=True, null=False, db_index=True)
bio = models.TextField(max_length=500, blank=True)
location = models.CharField(max_length=30, blank=True)
birth_date = models.DateField(null=True, blank=True)
@receiver(post_save, sender=User)
def create_user_profile(sender, instance, created, **kwargs):
if created:
Profile.objects.create(user=instance)
@receiver(post_save, sender=User)
def save_user_profile(sender, instance, **kwargs):
instance.profile.save()

Create a file named forms.py under home folder

from django.shortcuts import redirect, HttpResponseRedirect
from django.contrib.auth import logout
from django.contrib.auth.models import User
from home.models import Profile
from django import forms
class UserForm(forms.ModelForm):
class Meta:
model = User
fields = ('first_name', 'last_name', 'email')
class ProfileForm(forms.ModelForm):
class Meta:
model = Profile
fields = ('bio','location','birth_date')

Now, we specify the urls in home/urls.py

from django.conf.urls import url
from . import views
urlpatterns = [
url(r'^$', views.Home),
url(r'^profile/$', views.update_profile),
url(r'^account/logout/$', views.Logout),
]

Now the most important step is to create view. Open home/view.py

from django.shortcuts import render, get_object_or_404, redirect
from django.core.paginator import Paginator, EmptyPage, PageNotAnInteger
from django.contrib.auth.decorators import login_required
from django.contrib.auth.models import User
from django.contrib.auth import logout
from django.http import HttpResponseRedirect
from django.db import transaction
from .models import Profile
from .forms import UserForm,ProfileForm
@login_required
def Home(request):
return render(request, 'home/home.html')
@login_required
@transaction.atomic
def update_profile(request):
if request.method == 'POST':
user_form = UserForm(request.POST, instance=request.user)
profile_form = ProfileForm(request.POST, instance=request.user.profile)
if user_form.is_valid() and profile_form.is_valid():
user_form.save()
profile_form.save()
return HttpResponseRedirect('/')
else:
messages.error(request, _('Please correct the error below.'))
else:
user_form = UserForm(instance=request.user)
profile_form = ProfileForm(instance=request.user.profile)
return render(request, 'home/profile.html', {
'user_form': user_form,
'profile_form': profile_form
})
def Logout(request):
logout(request)
return HttpResponseRedirect('/')

So the Back-end part is done. Now comes the front-end part.

Create a folder templates under home. I am using materializecss for front end. 
base.html

{% load static %}
<html>
<head>
<!-- Materialize CSS -->
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/materialize/0.97.7/css/materialize.min.css">
<script src="https://cdnjs.cloudflare.com/ajax/libs/materialize/0.97.7/js/materialize.min.js"></script>
<!-- Material icons -->
<link href="https://fonts.googleapis.com/icon?family=Material+Icons" rel="stylesheet">
</head>
<title>Django</title>
{% if user.is_authenticated %}
<div class="navbar-fixed">
<nav class="blue">
<div class="nav-wrapper container">
<a href="/" class="brand-logo center">Google App</a>
<ul id="nav-mobile" class="right hide-on-med-and-down">
<li><a href="/account/logout">Log out</a></li>
</ul>
</div>
</nav>
</div>
{% endif %}
<div class="container">
{% block content %}
{% endblock %}
</div>
</html>

profile.html

{% extends ‘home/base.html’ %}
{% block content %}
<div class=”row”>
<div class=”col s12 m6 offset-m3">
<H3>Hi {{ user.email }}!</H3>
</div>
</div>
<form method=”post”>
{% csrf_token %}
{{ user_form.as_p }}
{{ profile_form.as_p }}
<button type=”submit”>Save changes</button>
</form>
{% endblock %}

home.html

{% extends 'home/base.html' %}
{% block content %}
<div class="row">
<div class="col s12 m6 offset-m3">
<H3>Hi {{ user.email }}!</H3>
</div>
</div>
{% endblock %}

Now create a folder registrations under template folder and add a

login.html

{% extends 'home/base.html' %}
{% block content %}
{% load static %}
<div class="container">
<div class="row">
<br><br>
<div class="col m6 card-panel white offset-m3" style="text-align:center">
<h1>Student Portal NIT DGP</h1>
<h4>Sign in to access all the facilities</h4>
<br>
<a href="{% url 'social:begin' 'google-oauth2' %}?next=/">
<img id="signInButton" src="http://www.setyourowntests.com/_/rsrc/1468869481521/help/accounts/btn_google_signin_dark_normal_web%402x.png" onclick="document.getElementById('signInButton').src='http://www.setyourowntests.com/_/rsrc/1468869481521/help/accounts/btn_google_signin_dark_normal_web%402x.png'">
</a>
<br>
</div>
</div>
</div>
{% endblock %}

And now we are ready to fire up the console.

$ python manage.py makemigrations
$ python manage.py migrate
$ python manage.py runserver
June 21, 2017 - 19:10:37
Django version 1.11, using settings 'login.settings'
Starting development server at http://127.0.0.1:8000/
Quit the server with CONTROL-C.

Open up the browser http://localhost:8000/

And the magic begins. :-)