Python social auth, Facebook, Twitter, and Google Auth
.htaccess:
# django AddHandler fcgid-script .fcgi RewriteEngine On RewriteCond %{REQUEST_FILENAME} !-f #RewriteCond %{REQUEST_URI} !^/static/ #RewriteRule ^(.*)$ hellodj.fcgi/$1 [QSA,L] #RewriteRule ^(.*)$ beerstash.fcgi/$1 [QSA,L] RewriteRule ^(.*)$ djauth.fcgi/$1 [QSA,L]
In the previous chapters, we'll learn how to use OAuth2 on a shared hosting environment.
Let's begin with a barebones Django project named djauth:
$ django-admin.py startproject djauth $ cd djauth $ python manage.py startapp djauthapp
After creating necessary files, the structure of the project looks like this:
djauth/settings.py:
""" Django settings for djauth project. Generated by 'django-admin startproject' using Django 1.8.2. For more information on this file, see https://docs.djangoproject.com/en/1.8/topics/settings/ For the full list of settings and their values, see https://docs.djangoproject.com/en/1.8/ref/settings/ """ # Build paths inside the project like this: os.path.join(BASE_DIR, ...) import os BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) # Quick-start development settings - unsuitable for production # See https://docs.djangoproject.com/en/1.8/howto/deployment/checklist/ # SECURITY WARNING: keep the secret key used in production secret! SECRET_KEY = '_6&fa3ui...y6rxh34pru;=mf&' # 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', 'djauthapp', 'social.apps.django_app.default', ) MIDDLEWARE_CLASSES = ( 'django.contrib.sessions.middleware.SessionMiddleware', 'django.middleware.common.CommonMiddleware', 'django.middleware.csrf.CsrfViewMiddleware', 'django.contrib.auth.middleware.AuthenticationMiddleware', 'django.contrib.auth.middleware.SessionAuthenticationMiddleware', 'django.contrib.messages.middleware.MessageMiddleware', 'django.middleware.clickjacking.XFrameOptionsMiddleware', 'django.middleware.security.SecurityMiddleware', ) TEMPLATE_CONTEXT_PROCESSORS = ( 'django.contrib.auth.context_processors.auth', 'django.core.context_processors.debug', 'django.core.context_processors.i18n', 'django.core.context_processors.media', 'django.core.context_processors.static', 'django.core.context_processors.tz', 'django.contrib.messages.context_processors.messages', 'social.apps.django_app.context_processors.backends', 'social.apps.django_app.context_processors.login_redirect', ) AUTHENTICATION_BACKENDS = ( 'social.backends.facebook.FacebookOAuth2', 'social.backends.google.GoogleOAuth2', 'social.backends.twitter.TwitterOAuth', 'django.contrib.auth.backends.ModelBackend', ) ROOT_URLCONF = 'djauth.urls' TEMPLATES = [ { 'BACKEND': 'django.template.backends.django.DjangoTemplates', 'DIRS': [], '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 = 'djauth.wsgi.application' # Database # https://docs.djangoproject.com/en/1.8/ref/settings/#databases DATABASES = { 'default': { 'ENGINE': 'django.db.backends.sqlite3', 'NAME': os.path.join(BASE_DIR, 'db.sqlite3'), } } # Internationalization # https://docs.djangoproject.com/en/1.8/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/1.8/howto/static-files/ STATIC_URL = '/static/' LOGIN_REDIRECT_URL = '/djsite' SOCIAL_AUTH_FACEBOOK_KEY = '16...535' SOCIAL_AUTH_FACEBOOK_SECRET = '857..4bb9d' SOCIAL_AUTH_GOOGLE_OAUTH2_KEY = '8507...kg6.apps.googleusercontent.com' SOCIAL_AUTH_GOOGLE_OAUTH2_SECRET = 'gUzw...CD32-' SOCIAL_AUTH_TWITTER_KEY = 'lNx...yQH8u' SOCIAL_AUTH_TWITTER_SECRET = '8virx...Div4dwB'
djauth/urls.py:
from django.conf.urls import patterns, include, url from django.contrib import admin admin.autodiscover() urlpatterns = patterns('', url(r'^$', 'djauthapp.views.home', name='home'), url(r'^admin/', include(admin.site.urls)), url('', include('social.apps.django_app.urls', namespace='social')), url('', include('django.contrib.auth.urls', namespace='auth')), )
djauthapp/views.py:
from django.shortcuts import render_to_response from django.template.context import RequestContext def home(request): context = RequestContext(request, {'request': request, 'user': request.user}) return render_to_response('home.html', context_instance=context)
djauthapp/templates/base.html:
<!DOCTYPE html> <html lang="en"> <head> <meta charset="utf-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta name="viewport" content="width=device-width, initial-scale=1"> <title>{% block title %}Authentication Tutorial{% endblock %}</title> <!-- Bootstrap --> <link href="/static/css/bootstrap.min.css" rel="stylesheet"> <link href="/static/css/bootstrap-theme.min.css" rel="stylesheet"> <link href="/static/css/fbposter.css" rel="stylesheet"> <!-- HTML5 Shim and Respond.js IE8 support of HTML5 elements and media queries --> <!-- WARNING: Respond.js doesn't work if you view the page via file:// --> <!--[if lt IE 9]> <script src="https://oss.maxcdn.com/libs/html5shiv/3.7.0/html5shiv.js"></script> <script src="https://oss.maxcdn.com/libs/respond.js/1.4.2/respond.min.js"></script> <![endif]--> </head> <body> {% block main %}{% endblock %} <!-- jQuery (necessary for Bootstrap's JavaScript plugins) --> <script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.0/jquery.min.js"></script> <!-- Include all compiled plugins (below), or include individual files as needed --> <script src="/static/js/bootstrap.min.js"></script> </body> </html>
djauthapp/templates/home.html:
{% extends 'base.html' %} {% block main %} <div> <h1>authentication demo</h1> <p> <ul> {% if user and not user.is_anonymous %} <li> <a>Hello {{ user.get_full_name|default:user.username }}!</a> </li> <li> <a href="{% url 'auth:logout' %}?next={{ request.path }}">Logout</a> </li> {% else %} <li> <a href="{% url 'social:begin' 'facebook' %}?next={{ request.path }}">Login with Facebook</a> </li> <li> <a href="{% url 'social:begin' 'google-oauth2' %}?next={{ request.path }}">Login with Google</a> </li> <li> <a href="{% url 'social:begin' 'twitter' %}?next={{ request.path }}">Login with Twitter</a> </li> {% endif %} </ul> </p> </div> {% endblock %}
Note that we return the user back to the original page from where it was requested to login. For that purpose, the usual next query-string argument is used, the value of this parameter will be stored in the session and later used to redirect the user when login was successful. In order to use it just define it with our link:
<a href="{% url 'social:begin' 'facebook' %}?next={{ request.path }}">Login with Facebook</a>
To get Client ID, please visit another tutorial page: Django Python Social Auth : Getting App ID (OAuth2) - Facebook, Twitter, and Google
We may get the following error when we try to "Login with Facebook":
"Given URL is not allowed by the Application configuration: One or more of the given URLs is not allowed by the App's settings. It must match the Website URL or Canvas URL, or the domain must be a subdomain of one of the App's domains."
So, we need to add Site URL, http://bogotobogo.com/djsite/.
Now, we can login with Facebook:
Let try "Login with Google:
We may get: something like "HTTPError 403 (Forbidden) with Django and python-social-auth connecting to Google with OAuth2"
We need to add the Google+ API to the list of enabled APIs on the Google Developer Console (under APIs) stackoverflow:
Now, if we try again "Login with Google:
Let try "Login with Twitter:
Ph.D. / Golden Gate Ave, San Francisco / Seoul National Univ / Carnegie Mellon / UC Berkeley / DevOps / Deep Learning / Visualization