[PYTHON] Create a social integration API for smartphone apps with Django

background

There are times when you want to link your own service account with an external service account such as facebook or Twitter using OAuth. For Python3, you can easily add an external account linkage screen for Web services by using python-social-auth. However, if you want to do the same with a smartphone app, you need to provide a link function with API, so a memo about how to handle it.

Purpose

This time, we assume the user takeover function in the smartphone app. The external services I want to use are facebook and Twitter. The following two functions are implemented.

  1. API to link an external account to an existing Django user
  2. API to get the associated Django user information from external account information

[Social Auth with Django REST Framework] (https://yeti.co/blog/social-auth-with-django-rest-framework/)

environment

Python 3.4.3 Django 1.8

Authentication flow

As the flow of authentication processing, the following usage using OAuth is assumed.

  1. Obtain an OAuth token for authentication by using various SDKs in the smartphone app
  1. Send the OAuth token obtained in 1. from the smartphone app to your service
  1. Obtain a user ID from an external service using the OAuth token received by your own service
  1. If the user ID can be obtained in 3., perform the necessary processing (linking user information, etc.) and return the processing result to the smartphone application.

Implementation details

Install python-social-auth

python


$ pip install python-social-auth

Settings for python-social-auth

settings.py


INSTALLED_APPS = (
    ...
    'social.apps.django_app.default',
    ...
)

TEMPLATE_CONTEXT_PROCESSORS = (
    ...
    'social.apps.django_app.context_processors.backends',
    'social.apps.django_app.context_processors.login_redirect',
    ...
)

AUTHENTICATION_BACKENDS = (
   'social.backends.facebook.FacebookOAuth2',
   'social.backends.twitter.TwitterOAuth',
   'django.contrib.auth.backends.ModelBackend',
)

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',
    #Remove the user so that it will not be created when checking the credentials.
    #'social.pipeline.user.create_user',
    'social.pipeline.social_auth.associate_user',
    'social.pipeline.social_auth.load_extra_data',
    'social.pipeline.user.user_details',
)

SOCIAL_AUTH_TWITTER_KEY = "MY_TWITTER_APP_KEY "
SOCIAL_AUTH_TWITTER_SECRET = "MY_TWITTER_APP_SECRET"

SOCIAL_AUTH_FACEBOOK_KEY = "MY_FACEBOOK_APP_ID"
SOCIAL_AUTH_FACEBOOK_SECRET = "MY_FACEBOOK_APP_SECRET"

Creating a table for authentication information

python


$ ./manage.py migrate

Project-wide url settings

myproject/urls.py


from django.conf.urls import url

urlpatterns = [
    ...
    url('', include('social.apps.django_app.urls', namespace='social'))
    ...
]

URL setting of the app you want to use the linkage function

myapp/urls.py


from django.conf.urls import url
from . import views

urlpatterns = [
	# 1.API to link an external account to an existing user
    url(r'api/associate/(?P<backend>[^/]+)/$', views.associate_account, name='associate_account'),
	# 2.API to get linked user information from external account information
    url(r'api/auth/(?P<backend>[^/]+)/$', views.auth_account, name='auth_account'),
]

View of the app you want to use the linkage function

myapp/views.py


from django.contrib.auth import login

from rest_framework import status
from rest_framework.response import Response
from rest_framework.permissions import IsAuthenticated
from rest_framework.decorators import api_view, permission_classes

from social.backends.oauth import BaseOAuth1, BaseOAuth2
from social.apps.django_app.utils import psa

# 1.API to link an external account to an existing user

@api_view(('POST',))
@permission_classes((IsAuthenticated,))
@psa('social:complete')
def associate_account(request, backend):
    backend = request.backend
    token = _make_token(request, backend)
    #User is returned only when authentication with OAuth is successful
    user = backend.do_auth(token, user=request.user)
    if user:
        login(request, user)
        return Response({'success': True})
    else:
        return Response({"errors": "Error with social authentication"},
                            status=status.HTTP_400_BAD_REQUEST)

# 2.API to get linked user information from external account information

@api_view(('POST',))
@psa('social:complete')
def auth_account(request, backend):
    backend = request.backend
    token = _make_token(request, backend)
    #User is returned only when authentication with OAuth is successful and there is a user associated with that information
    user = backend.do_auth(token)
    if user:
        return Response({'id': user.id, 'username': user.username})
    else:
        return Response({"errors": "User Not Found"},
                            status=status.HTTP_404_NOT_FOUND)

#The shape of the token used is different between OAuth1 and OAuth2

def _make_token(request, backend):
    if isinstance(backend, BaseOAuth1):
        token = {
            'oauth_token': request.data.get('access_token'),
            'oauth_token_secret': request.data.get('access_token_secret'),
        }
    elif isinstance(backend, BaseOAuth2):
        token = request.data.get('access_token')
    return token

Operation check

Cooperation with Twitter

Preparation

  1. Prepare an access_token and access_token_secret (in some way) for the user linked with your own Twitter app.
  2. Log in to the management screen of your own service with a browser.

How to check the external service linkage function

Access the URL (ex. Http://myserver/myapp/api/associate/twitter/) with associate_account set with a browser.

Django_REST_framework.png

As shown in the screen above, enter access_token and access_token_secret in json format in content and press [POST].

{
   "access_token": "my_access_token",
   "access_token_secret": "my_access_token_secret"
}

If {" success ": true} is returned, authentication is successful.

Django_REST_framework.png

How to check the external service authentication function

Access the URL (ex. Http://myserver/myapp/api/auth/twitter/) for which auth_account is set with a browser, and perform the same procedure as in the previous section.

Success if the ID of the user who linked earlier is returned.

Django_REST_framework.png

For Facebook

You can check it with almost the same procedure as Twitter, but the following two points are different.

  1. In the above confirmation procedure, change the place where it is twitter to facebook.
  2. The only json information to send is ʻaccess_token. (OAuth2 does not have ʻaccess_token_secret)

Impressions

python-social-auth Convenient! I was able to write the code required for authentication in just a few lines!

However, this implementation seems to have finally been realized by gathering various scattered English information, and I got the impression that Python has little information in Japanese.

reference

I want to log in on Twitter and Facebook with Python 3.4 and Django 1.6.5-Today's Hack http://narusemotoki.tumblr.com/post/90525892180/python-34%E3%81%A8django-165%E3%81%A7twitter%E3%82%84facebook%E3%81%A7%E3%81%AE%E3%83%AD%E3%82%B0%E3%82%A4%E3%83%B3%E3%82%92%E3%81%97%E3%81%9F%E3%81%84

omab/python-social-auth https://github.com/omab/python-social-auth

Django Framework — Python Social Auth documentation https://python-social-auth.readthedocs.org/en/latest/configuration/django.html

Pipeline — Python Social Auth documentation https://python-social-auth.readthedocs.org/en/latest/pipeline.html#authentication-pipeline

Use Cases — Python Social Auth documentation http://psa.matiasaguirre.net/docs/use_cases.html#signup-by-oauth-access-token

Twitter OAuth using access_token · Issue #272 · omab/python-social-auth https://github.com/omab/python-social-auth/issues/272

Social Auth with Django REST Framework - Yeti https://yeti.co/blog/social-auth-with-django-rest-framework/

Recommended Posts

Create a social integration API for smartphone apps with Django
Create a dashboard for Network devices with Django!
Create an API with Django
Create a homepage with django
Create a web API that can deliver images with Django
(For beginners) Try creating a simple web API with Django
Create a file uploader with Django
[Python] Create a screen for HTTP status code 403/404/500 with Django
Create a REST API to operate dynamodb with the Django REST Framework
Create a model for your Django schedule
Create a LINE BOT with Minette for Python
Create a one-file hello world application with django
How to create a Rest Api in Django
Create a clean DB for testing with FastAPI and unittest the API with pytest
Create a Django schedule
Create a typed web app with Python's web framework "Fast API" and TypeScript / OpenAPI-Technology stack for machine learning web apps
Create a Todo app with Django REST Framework + Angular
I tried to create a table only with Django
Create a Todo app with the Django REST framework
Create a Todo app with Django ③ Create a task list page
Create a tweet heatmap with the Google Maps API
Create a Layer for AWS Lambda Python with Docker
Create a Todo app with Django ⑤ Create a task editing function
Create a django environment with docker-compose (MariaDB + Nginx + uWSGI)
Build a Django environment for Win10 (with virtual space)
Django beginners create simple apps 3
[Memo] Build a development environment for Django + Nuxt.js with Docker
Django beginners create simple apps 1
Recommendations for django, wagtail ~ Why develop a website with python ~
Create a child account for connect with Stripe in Python
[Django] Create a model suitable for phone numbers / zip codes
Create a Twitter BOT with the GoogleAppEngine SDK for Python
Django beginners create simple apps 2
Create a Django login screen
Tornado-Let's create a Web API that easily returns JSON with JSON
Create a Todo app with Django ① Build an environment with Docker
Create a directory with python
Qiita API Oauth with Django
Django beginners create simple apps 5
Create an alias for Route53 to CloudFront with the AWS API
Create a temporary file with django as a zip file and return it
[Python / Django] Create a web API that responds in JSON format
Create a striped illusion with gamma correction for Python3 and openCV3
Rails users try to create a simple blog engine with Django
How to create a label (mask) for segmentation with labelme (semantic segmentation mask)
[LINE Messaging API] Create a BOT that connects with someone with Python
Create an environment for Django x Apache x mod_wsgi with Vagrant (Ubuntu 16.04)
Create a development environment for Go + MySQL + nginx with Docker (docker-compose)
I made a development environment for Django 3.0 with Docker, Docker-compose, Poetry
Try to create a Qiita article with REST API [Environmental preparation]
Create a USB boot Ubuntu with a Python environment for data analysis
Create and return a CP932 CSV file for Excel with Chalice
How to create a serverless machine learning API with AWS Lambda
[DynamoDB] [Docker] Build a development environment for DynamoDB and Django with docker-compose
Set up social login with Django
[AWS] Create API with API Gateway + Lambda
Steps to create a Django project
Deploy a Django application with Docker
Create a virtual environment with Python!
Django Tips-Create a ranking site with Django-
Build a web application with Django