EzDevInfo.com

python-social-auth

Social auth made simple Python Social Auth

Facebook Auth with AngularJS and Django REST Framework

I am developing a SPA application with AngularJS which uses Django backend for the server. The way that I communicate with the server from the SPA is with django-rest-framework. So now I want to make authentication with facebook (google and twitter too) and I read a lot on this topic and found OAuth.io which is making the authetication on the client SPA side and python-social-auth which is doing the same thing but on the server side.

So currently I have only the client auth, my app is connecting to facebook (with OAuth.io) and login successfully. This process is returning access_token and then I am making a request to my API which have to login this user or create account for this user by given token and this part is not working. So I am not sure where I am wrong, maybe because there isn't a full tutorial about using python-social-auth so maybe I am missing something or.. I don't know..

So some code of this what I have:

On the SPA side: This is the connection with OAuth.io and is working because I am getting the access token. Then I have to make a request to my rest API. backend is 'facebook', 'google' or 'twitter'

OAuth.initialize('my-auth-code-for-oauthio');
OAuth.popup(backend, function(error, result) {
    //handle error with error
    //use result.access_token in your API request

    var token = 'Token ' + result.access_token;
    var loginPromise = $http({
         method:'POST', 
         url: 'api-token/login/' + backend + '/', 
         headers: {'Authorization': token}});

         loginPromise.success(function () {
             console.log('Succeess');
         });
         loginPromise.error(function (result) {
             console.log('error');
         });
});

On the server in my settings.py I have added social plugin to the installed apps, template context preprocessors, some auth backends and that is my file:

INSTALLED_APPS = (
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    ...,
    'rest_framework',
    'rest_framework.authtoken',
    'api',
    'social.apps.django_app.default',
    'social'
)
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.request",
                               "django.contrib.messages.context_processors.messages",
                               'social.apps.django_app.context_processors.backends',
                               'social.apps.django_app.context_processors.login_redirect',)

REST_FRAMEWORK = {
    'DEFAULT_AUTHENTICATION_CLASSES': (
        'rest_framework.authentication.TokenAuthentication',
    )
}

SOCIAL_AUTH_FACEBOOK_KEY = 'key'
SOCIAL_AUTH_FACEBOOK_SECRET = 'secret'
SOCIAL_AUTH_FACEBOOK_SCOPE = ['email']

AUTHENTICATION_BACKENDS = (
      'social.backends.open_id.OpenIdAuth',
      'social.backends.facebook.FacebookOAuth2',
      'social.backends.facebook.FacebookAppOAuth',
      'social.backends.google.GoogleOpenId',
      'social.backends.google.GoogleOAuth2',
      'social.backends.google.GoogleOAuth',
      'social.backends.twitter.TwitterOAuth',
      'django.contrib.auth.backends.ModelBackend',
  )

In my views.py of the API I have the following (I found it here):

from django.contrib.auth.models import User, Group
from rest_framework import viewsets, generics
from rest_framework.views import APIView
from rest_framework.response import Response
from rest_framework import authentication, permissions, parsers, renderers
from rest_framework.authtoken.serializers import AuthTokenSerializer
from rest_framework.decorators import api_view, throttle_classes
from social.apps.django_app.utils import strategy
from rest_framework.permissions import IsAuthenticated, IsAuthenticatedOrReadOnly

from django.contrib.auth import get_user_model
from django.db.models.signals import post_save
from django.dispatch import receiver
from rest_framework.authtoken.models import Token

class ObtainAuthToken(APIView):
    throttle_classes = ()
    permission_classes = ()
    parser_classes = (parsers.FormParser, parsers.MultiPartParser, parsers.JSONParser,)
    renderer_classes = (renderers.JSONRenderer,)
    serializer_class = AuthTokenSerializer
    model = Token

    # Accept backend as a parameter and 'auth' for a login / pass
    def post(self, request, backend):
        serializer = self.serializer_class(data=request.DATA)

        if backend == 'auth':
            if serializer.is_valid():
                token, created = Token.objects.get_or_create(user=serializer.object['user'])
                return Response({'token': token.key})
            return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)

        else:
            # Here we call PSA to authenticate like we would if we used PSA on server side.
            user = register_by_access_token(request, backend)

            # If user is active we get or create the REST token and send it back with user data
            if user and user.is_active:
                token, created = Token.objects.get_or_create(user=user)
                return Response({'id': user.id , 'name': user.username, 'userRole': 'user','token': token.key})

@strategy()
def register_by_access_token(request, backend):
    backend = request.strategy.backend
    user = request.user
    user = backend._do_auth(
        access_token=request.GET.get('access_token'),
        user=user.is_authenticated() and user or None
    )
    return user

And finally I have these routes in urls.py:

...
url(r'^api-auth/', include('rest_framework.urls', namespace='rest_framework')),
url(r'^api-token-auth/', 'rest_framework.authtoken.views.obtain_auth_token'),
url(r'^api-token/login/(?P<backend>[^/]+)/$', views.ObtainAuthToken.as_view()),
url(r'^register/(?P<backend>[^/]+)/', views.register_by_access_token),
...

Everytime when I try to do auth, OAuth.io is working and the rqest to api returns

detail: "Invalid token"

I think that I missed something in the configuration of python-social-auth or I am doing everything wrong. So I will be glad if anyone has some ideas and want to help :)


Source: (StackOverflow)

Python Social Auth Django template example

Does someone has an open example using Python Social Auth with Django in templates?

I took a look in their Github repo, and in the django exmaple, there is nothing about how to deal with it in templates (e.g. doing login, logout, etc).


Source: (StackOverflow)

Advertisements

oauth2 token authentication using django-oauth-toolkit and python-social-auth

I'm building an API using Django Rest Framework. Later this API is supposed to be consumed by iOS and Android devices. I want to allow my users to sign-up with oauth2-providers like Facebook and Google. In this case, they shouldn't have to create an account with my platform at all. But users should also be able to sign-up when not having a Facebook/Google account, for which I'm using django-oauth-toolkit, so I have my own oauth2-provider.

For external providers I'm using python-social-auth, which works fine and automatically creates the user objects.

I want the clients to authenticate by using bearer tokens, which works fine for users that signed up with my provider (django-oauth-toolkit provides authentication scheme and permission classes for Django REST Framework).
However, python-social-auth only implements session based authentication, so there is no straightforward way to make authenticated API requests on behalf of users that registered by an external oauth2 provider.

If I use an access_token that has been generated by django-oauth-toolkit, doing a request like this works:

curl -v -H "Authorization: Bearer <token_generated_by_django-oauth-toolkit>" http://localhost:8000/api/

However, the following doesn't work since there is no corresponding authentication scheme for Django REST Framework and the AUTHENTICATION_BACKENDS provided by python-social-auth only work for session-based authentication:

curl -v -H "Authorization: Bearer <token_stored_by_python-social-auth>" http://localhost:8000/api/

Using the browseable API provided by Django REST Framework after authenticating with python-social-auth works just fine, only API calls without a session cookie don't work.

I'm wondering what the best approach is for this problem. The way I see it, I have basically two options:

A: When a user signs up with an external oauth2 provider (handled by python-social-auth), hook into the process to create an oauth2_provider.models.AccessToken and continue to use 'oauth2_provider.ext.rest_framework.OAuth2Authentication', now authenticating also users that registered with an external provider. This approach is suggested here: https://groups.google.com/d/msg/django-rest-framework/ACKx1kY7kZM/YPWFA2DP9LwJ

B: Use python-social-auth for API request authentication. I could get my own users into python-social-auth by writing a custom backend and using register_by_access_token. However, since API calls cannot utilize Django sessions this would mean I would have to write an authentication scheme for Django Rest Framework that utilizes the data stored by python-social-auth. Some pointers on how to do this can be found here:
http://psa.matiasaguirre.net/docs/use_cases.html#signup-by-oauth-access-token
http://blog.wizer.fr/2013/11/angularjs-facebook-with-a-django-rest-api/
http://cbdev.blogspot.it/2014/02/facebook-login-with-angularjs-django.html
However, the way I understand it python-social-auth only verifies the token when doing a login and relies on the Django session afterwards. This would mean I would have to find a way to prevent python-social-auth from doing the whole oauth2-flow for each stateless API request and rather check against the data stored in the DB, which isn't really optimized for querying since it's stored as JSON (I could use UserSocialAuth.objects.get(extra_data__contains=) though).
I would also have to take care of verifying the scopes of an access token and use them to check permissions, something django-oauth-toolkit already does (TokenHasScope, required_scopes etc).

At the moment, I'm leaning towards using option A, since django-oauth-toolkit provides good integration with Django Rest Framework and I get everything I need out of the box. The only drawback is that I have to "inject" the access_tokens retrieved by python-social-auth into the AccessToken model of django-oauth-toolkit, which feels wrong somehow, but would probably be by far the easiest approach.

Does anybody have any objections on doing that or has maybe tackled the same problem in a different way? Am I missing something obvious and making my life harder than necessary? If anybody has already integrated django-oauth-toolkit with python-social-auth and external oauth2 providers I would be very thankful for some pointers or opinions.


Source: (StackOverflow)

python-social-auth AuthCanceled exception

I'm using python-social-auth in my Django application for authentication via Facebook. But when a user tries to login and when it's been refirected to Facebook app page clicks on "Cancel" button, appears the following exception:

ERROR 2014-01-03 15:32:15,308 base :: Internal Server Error: /complete/facebook/
Traceback (most recent call last):
  File "/home/vera/virtualenv/myapp/local/lib/python2.7/site-packages/django/core/handlers/base.py", line 114, in get_response
    response = wrapped_callback(request, *callback_args, **callback_kwargs)
  File "/home/vera/virtualenv/myapp/local/lib/python2.7/site-packages/django/views/decorators/csrf.py", line 57, in wrapped_view
    return view_func(*args, **kwargs)
  File "/home/vera/virtualenv/myapp/local/lib/python2.7/site-packages/social/apps/django_app/utils.py", line 45, in wrapper
    return func(request, backend, *args, **kwargs)
  File "/home/vera/virtualenv/myapp/local/lib/python2.7/site-packages/social/apps/django_app/views.py", line 21, in complete
    redirect_name=REDIRECT_FIELD_NAME, *args, **kwargs)
  File "/home/vera/virtualenv/myapp/local/lib/python2.7/site-packages/social/actions.py", line 54, in do_complete
    *args, **kwargs)
  File "/home/vera/virtualenv/myapp/local/lib/python2.7/site-packages/social/strategies/base.py", line 62, in complete
    return self.backend.auth_complete(*args, **kwargs)
  File "/home/vera/virtualenv/myapp/local/lib/python2.7/site-packages/social/backends/facebook.py", line 63, in auth_complete
    self.process_error(self.data)
  File "/home/vera/virtualenv/myapp/local/lib/python2.7/site-packages/social/backends/facebook.py", line 56, in process_error
    super(FacebookOAuth2, self).process_error(data)
  File "/home/vera/virtualenv/myapp/local/lib/python2.7/site-packages/social/backends/oauth.py", line 312, in process_error
    raise AuthCanceled(self, data.get('error_description', ''))
AuthCanceled: Authentication process canceled

Is the any way to catch it Django?


Source: (StackOverflow)

Python Social auth authentication via access-token fails

I am currently developing a serverbackand with Django (1.7) that should handle authentication via social Networks by using python-social-auth. I followed the Tutorial on this site, which describes the process for a simple Webapp. This worked perfectly for Google and Twitter login.

Since the Server should be just a REST-FULL Backend I decided to get the Access-Token on the client side and send it to the server. The server than will authenticate with it. This process should be no problem and is even given as an example in the docs of python-social-auth.

However if I do set everything up I will receive an error that says: "Backend not Found 404".

Here a minimal part of the project:

settings.py: (I also included API_KEY and SECRET)

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

views.py (for the authentication view)

from django.contrib.auth import login

from social.apps.django_app.utils import psa

@psa('social:complete')
def register_by_access_token(request, backend):
    token = request.GET.get('access_token')
    user = request.backend.do_auth(request.GET.get('access_token'))
    if user:
        login(request, user)
        return 'OK'
    else:
        return 'ERROR'

This i copied strait from the docs and only changed backend.do_auth to request.backend.do_auth. This seems to be an error in the docs.

urls.py:

...
url(r'^register-by-token/(?P<backend>[^/]+)/$', 'register_by_access_token')
...

Also as suggested in the docs.

I just tried to get this working just for google-oauth because there is a simple js-lib that gives you the access-token. This also worked quite nice and I send a request to

GET http://localhost:8000/register-by-token/google-oauth2/<access-token>/

As described above the return was a 404 Backend not found. I did a little bit of debugging and found out that the error is raised in the login function not the do_auth() function of the backend. Therefor the actual authentication process works. I also tried using a random generated string as a token and got an according error, that the user cannot be authenticated.

The funny thing is that the user even has a property backend which holds 'social.backends.google.GoogleOAuth2' as it should.

Thank you if you stayed with me for the long post, and I hope someone has an idea what could be wrong :). Looking forward to your answers.


Source: (StackOverflow)

how to get user email with python social auth with facebook and save it

I'm trying to implement python-social-auth in django.

I want users to authenticate through facebook and save their email.

I'm able to authenticate users but the extended permission for email is not showing up in the facebook authentification box and it's not storing the email in the database.

In settings.py I have the follwoing:

SOCIAL_AUTH_FACEBOOK_KEY='xxx'
SOCIAL_AUTH_FACEBOOK_SECRET='xxx'
FACEBOOK_EXTENDED_PERMISSIONS = ['email']

AUTHENTICATION_BACKENDS = (
    'social.backends.facebook.FacebookOAuth2',
    'social.backends.email.EmailAuth',
    'django.contrib.auth.backends.ModelBackend',
)

LOGIN_URL = '/login/'
LOGIN_REDIRECT_URL = '/done/'
LOGOUT_REDIRECT_URL = '/'
URL_PATH = ''
SOCIAL_AUTH_STRATEGY = 'social.strategies.django_strategy.DjangoStrategy'
SOCIAL_AUTH_STORAGE = 'social.apps.django_app.default.models.DjangoStorage'

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.social_auth.associate_by_email',
    # 'users.pipeline.require_email',
    'social.pipeline.mail.mail_validation',
    'social.pipeline.user.create_user',
    'social.pipeline.social_auth.associate_user',
    'social.pipeline.social_auth.load_extra_data',
    'social.pipeline.user.user_details'
)

The facebook dialog box...

enter image description here

How can I solve this?


Source: (StackOverflow)

How to retrieve Facebook friend's information with Python-Social-auth and Django

How could I retrieve Facebook friend's information using Python-Social-auth and Django? I already retrive a profile information and authenticate the user, but I want to get more information about their friends and envite them to my app. Thanks!


Source: (StackOverflow)

Python Social Auth- import error when using Google Authentication

I successfully followed along this blog entry more than a month ago:http://www.artandlogic.com/blog/2014/04/tutorial-adding-facebooktwittergoogle-authentication-to-a-django-application/

When I created a new environment, and recreated the steps, I'm now getting an import error, no module named google_auth during template rendering.

It traces back to this line:

<a rel='nofollow' href="{% url 'social:begin' 'google-oauth2' %}?next={{ request.path }}">Login</a>

It looks like django is not looking in the social app for the correct template processing? Any ideas on why this is no longer working?

#settings.py
INSTALLED_APPS = (... , 'social.apps.django_app.default', ...)

AUTHENTICATION_BACKENDS = ('social.backends.google.GoogleOAuth2', 'django.contrib.auth.backends.ModelBackend')

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')

#urls.py
urlpatterns = patterns('', 
url('', include('social.apps.django_app.urls', namespace='social')),
url('', include('django.contrib.auth.urls', namespace='auth')),
url(r'^$', 'app.views.home', name='home'),
)

EDIT: Full traceback below

Environment:
Request Method: GET

Django Version: 1.7
Python Version: 2.7.8
Installed Applications:
('django.contrib.admin',
 'django.contrib.auth',
 'django.contrib.contenttypes',
 'django.contrib.sessions',
 'django.contrib.messages',
 'django.contrib.staticfiles',
 'charts',
 'social.apps.django_app.default',
 'djcelery',
 'kombu.transport.django')
Installed Middleware:
('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',
 'social.apps.django_app.middleware.SocialAuthExceptionMiddleware',
 'charts.middleware.SocialAuthExceptionMiddleware')


Template error:
In template charts/templates/base.html, error at line 69
   No module named google_auth
   59 :           </ul>


   60 :         </li>


   61 :         <li>


   62 :           Hello, <strong>{{ user.get_full_name|default:user.username }}</strong>!


   63 :         </li>


   64 :         <li>


   65 :           <a rel='nofollow' href="{% url 'auth:logout' %}?next={{ request.path }}">Logout</a>


   66 :         </li>


   67 :         {% else %}


   68 :         <li>


   69 :           <a rel='nofollow' href=" {% url 'social:begin' 'google-oauth2' %} ?next={{ request.path }}">Login</a>


   70 :         </li>


   71 :         {% endif %}


   72 :       </ul>


   73 :     </nav>


   74 : </head>


   75 : <body>


   76 : {% block content %}


   77 : {% endblock %}


   78 : <div id="footer">


   79 :     <center>


Traceback:
File "//anaconda/envs/analytics/lib/python2.7/site-packages/django/core/handlers/base.py" in get_response
  111.                     response = wrapped_callback(request, *callback_args, **callback_kwargs)
File "/charts/views.py" in home
  743.                              context_instance=context)
File "//anaconda/envs/analytics/lib/python2.7/site-packages/django/shortcuts.py" in render_to_response
  23.     return HttpResponse(loader.render_to_string(*args, **kwargs), **httpresponse_kwargs)
File "//anaconda/envs/analytics/lib/python2.7/site-packages/django/template/loader.py" in render_to_string
  174.         return t.render(context_instance)
File "//anaconda/envs/analytics/lib/python2.7/site-packages/django/template/base.py" in render
  148.             return self._render(context)
File "//anaconda/envs/analytics/lib/python2.7/site-packages/django/template/base.py" in _render
  142.         return self.nodelist.render(context)
File "//anaconda/envs/analytics/lib/python2.7/site-packages/django/template/base.py" in render
  844.                 bit = self.render_node(node, context)
File "//anaconda/envs/analytics/lib/python2.7/site-packages/django/template/debug.py" in render_node
  80.             return node.render(context)
File "//anaconda/envs/analytics/lib/python2.7/site-packages/django/template/loader_tags.py" in render
  126.         return compiled_parent._render(context)
File "//anaconda/envs/analytics/lib/python2.7/site-packages/django/template/base.py" in _render
  142.         return self.nodelist.render(context)
File "//anaconda/envs/analytics/lib/python2.7/site-packages/django/template/base.py" in render
  844.                 bit = self.render_node(node, context)
File "//anaconda/envs/analytics/lib/python2.7/site-packages/django/template/debug.py" in render_node
  80.             return node.render(context)
File "//anaconda/envs/analytics/lib/python2.7/site-packages/django/template/defaulttags.py" in render
  312.                 return nodelist.render(context)
File "//anaconda/envs/analytics/lib/python2.7/site-packages/django/template/base.py" in render
  844.                 bit = self.render_node(node, context)
File "//anaconda/envs/analytics/lib/python2.7/site-packages/django/template/debug.py" in render_node
  80.             return node.render(context)
File "//anaconda/envs/analytics/lib/python2.7/site-packages/django/template/defaulttags.py" in render
  444.             url = reverse(view_name, args=args, kwargs=kwargs, current_app=context.current_app)
File "//anaconda/envs/analytics/lib/python2.7/site-packages/django/core/urlresolvers.py" in reverse
  517.                 app_list = resolver.app_dict[ns]
File "//anaconda/envs/analytics/lib/python2.7/site-packages/django/core/urlresolvers.py" in app_dict
  329.             self._populate()
File "//anaconda/envs/analytics/lib/python2.7/site-packages/django/core/urlresolvers.py" in _populate
  303.                 lookups.appendlist(pattern.callback, (bits, p_pattern, pattern.default_args))
File "//anaconda/envs/analytics/lib/python2.7/site-packages/django/core/urlresolvers.py" in callback
  231.         self._callback = get_callable(self._callback_str)
File "//anaconda/envs/analytics/lib/python2.7/site-packages/django/utils/lru_cache.py" in wrapper
  101.                     result = user_function(*args, **kwds)
File "//anaconda/envs/analytics/lib/python2.7/site-packages/django/core/urlresolvers.py" in get_callable
  101.                     not module_has_submodule(import_module(parentmod), submod)):
File "//anaconda/envs/analytics/lib/python2.7/importlib/__init__.py" in import_module
  37.     __import__(name)

Exception Type: ImportError at /
Exception Value: No module named google_auth

Source: (StackOverflow)

Duplicate email using both python-social-auth and email registration in Django

I'm using both python-social-auth and email registration in my project. For the user model I use a subclass of AbstractBaseUser:

class User(AbstractBaseUser):
    USERNAME_FIELD = 'email'


AUTH_USER_MODEL = 'userprofile.User'

But when a user that is registered with his email (demo@demo.com) and password tries to login with his Facebook account that is associated with the same email address, I get the following error:

IntegrityError at /social/complete/facebook/
duplicate key value violates unique constraint "userprofile_user_email_key"
DETAIL:  Key (email)=(demo@demo.com) already exists.

/Users/vera/.virtualenvs/app/lib/python2.7/site-packages/django/core/handlers/base.py in get_response
                    response = wrapped_callback(request, *callback_args, **callback_kwargs) ...
/Users/vera/.virtualenvs/app/lib/python2.7/site-packages/django/views/decorators/csrf.py in wrapped_view
        return view_func(*args, **kwargs) ...
/Users/vera/.virtualenvs/app/lib/python2.7/site-packages/social/apps/django_app/utils.py in wrapper
            return func(request, backend, *args, **kwargs) ...
/Users/vera/.virtualenvs/app/lib/python2.7/site-packages/social/apps/django_app/views.py in complete
                       redirect_name=REDIRECT_FIELD_NAME, *args, **kwargs) ...
/Users/vera/.virtualenvs/app/lib/python2.7/site-packages/social/actions.py in do_complete
                                 *args, **kwargs) ...
/Users/vera/.virtualenvs/app/lib/python2.7/site-packages/social/strategies/base.py in complete
        return self.backend.auth_complete(*args, **kwargs) ...
/Users/vera/.virtualenvs/app/lib/python2.7/site-packages/social/backends/facebook.py in auth_complete
        return self.do_auth(access_token, response, *args, **kwargs) ...
/Users/vera/.virtualenvs/app/lib/python2.7/site-packages/social/backends/facebook.py in do_auth
        return self.strategy.authenticate(*args, **kwargs) ...
/Users/vera/.virtualenvs/app/lib/python2.7/site-packages/social/strategies/django_strategy.py in authenticate
        return authenticate(*args, **kwargs) ...
/Users/vera/.virtualenvs/app/lib/python2.7/site-packages/django/contrib/auth/__init__.py in authenticate
            user = backend.authenticate(**credentials) ...
/Users/vera/.virtualenvs/app/lib/python2.7/site-packages/social/backends/base.py in authenticate
        return self.pipeline(pipeline, *args, **kwargs) ...
/Users/vera/.virtualenvs/app/lib/python2.7/site-packages/social/backends/base.py in pipeline
        out = self.run_pipeline(pipeline, pipeline_index, *args, **kwargs) ...
/Users/vera/.virtualenvs/app/lib/python2.7/site-packages/social/backends/base.py in run_pipeline
            result = func(*args, **out) or {} ...
/Users/vera/.virtualenvs/app/lib/python2.7/site-packages/social/pipeline/user.py in user_details
            strategy.storage.user.changed(user) ...
/Users/vera/.virtualenvs/app/lib/python2.7/site-packages/social/storage/django_orm.py in changed
        user.save() ...
/Users/vera/.virtualenvs/app/lib/python2.7/site-packages/django/db/models/base.py in save
                       force_update=force_update, update_fields=update_fields) ...
/Users/vera/.virtualenvs/app/lib/python2.7/site-packages/django/db/models/base.py in save_base
            updated = self._save_table(raw, cls, force_insert, force_update, using, update_fields) ...
/Users/vera/.virtualenvs/app/lib/python2.7/site-packages/django/db/models/base.py in _save_table
                                      forced_update) ...
/Users/vera/.virtualenvs/app/lib/python2.7/site-packages/django/db/models/base.py in _do_update
        return filtered._update(values) > 0 ...
/Users/vera/.virtualenvs/app/lib/python2.7/site-packages/django/db/models/query.py in _update
        return query.get_compiler(self.db).execute_sql(None) ...
/Users/vera/.virtualenvs/app/lib/python2.7/site-packages/django/db/models/sql/compiler.py in execute_sql
        cursor = super(SQLUpdateCompiler, self).execute_sql(result_type) ...
/Users/vera/.virtualenvs/app/lib/python2.7/site-packages/django/db/models/sql/compiler.py in execute_sql
        cursor.execute(sql, params) ...
/Users/vera/.virtualenvs/app/lib/python2.7/site-packages/debug_toolbar/panels/sql/tracking.py in execute
        return self._record(self.cursor.execute, sql, params) ...
/Users/vera/.virtualenvs/app/lib/python2.7/site-packages/debug_toolbar/panels/sql/tracking.py in _record
            return method(sql, params) ...
/Users/vera/.virtualenvs/app/lib/python2.7/site-packages/django/db/backends/util.py in execute
            return super(CursorDebugWrapper, self).execute(sql, params) ...
/Users/vera/.virtualenvs/app/lib/python2.7/site-packages/django/db/backends/util.py in execute
                return self.cursor.execute(sql, params) ...
/Users/vera/.virtualenvs/app/lib/python2.7/site-packages/django/db/utils.py in __exit__
                six.reraise(dj_exc_type, dj_exc_value, traceback) ...
/Users/vera/.virtualenvs/app/lib/python2.7/site-packages/django/db/backends/util.py in execute
                return self.cursor.execute(sql, params) ...

When somebody registers with his Facebook account and then logs in everything works fine. The problem appears when he registers with his email (I'm using django-registration), so we have an instance of User (but not UserSocialAuth), and then we tries to login with his Facebook account associated the same email address.


Source: (StackOverflow)

How do I migrate users from OpenID to Google OAuth2/OpenID Connect using Python Social Auth?

Google is deprecating the OpenID endpoint I was using (v1.0 I think, via the django_openid_auth module) and I need to update my app and migrate my users' accounts to use Google OAuth2.

I've changed the app to use python-social-auth and have it authenticating with social.backends.google.GoogleOAuth2 successfully.

I've written a pipeline function to find associated OpenID urls from the old table and this is working for the other backends I care about but Google:

def associate_legacy_user(backend, response, uid=None, user=None,
                          *args, **kwargs):
    if uid and not user:
        # Try to associate accounts registered in the old openid table
        identity_url = None

        if backend.name == 'google-oauth2':
            # TODO: this isn't working
            identity_url = response.get('open_id')

        else:
            # for all other backends, see if there is a claimed_id url
            # matching the identity_url use identity_url instead of uid
            # as uid may be the user's email or username
            try:
                identity_url = response.identity_url
            except AttributeError:
                identity_url = uid

        if identity_url:
            # raw sql as this is no longer an installed app
            user_ids = sql_query.dbquery('SELECT user_id '
                                         'FROM django_openid_auth_useropenid '
                                         'WHERE claimed_id = %s',
                                         (identity_url,))

            if len(user_ids) == 1:
                return {'user': User.objects.get(id=user_ids[0]['user_id'])}

As best I can tell from reading Google's migration guide, I need to add an openid.realm to the request, which I've done as follows in settings.py:

SOCIAL_AUTH_GOOGLE_OAUTH2_AUTH_EXTRA_ARGUMENTS \
    = {'openid.realm': 'http://example.com/'}

But this doesn't seem to be returning the open_id value in the response passed into my pipeline function.

I seem to be stuck on Step 3:

  • I tried sub-classing the backend to change the RESPONSE_TYPE to add id_token but that returned an empty response:

    import social.backends.google
    class CustomGoogleOAuth2(social.backends.google.GoogleOAuth2):
        RESPONSE_TYPE = 'code id_token'
    
  • I tried building an additional request to https://www.googleapis.com/oauth2/v3/token similar to this example, but I don't really know how to go about putting that together and debugging it.

Some more details:

  • My old claimed_ids for Google OpenID users look like: https://www.google.com/accounts/o8/id?id=AItOawmAW18QuHDdn6PZzaiI5BWUb84mZzNB9eo
  • I'm happy to use social.backends.google.GoogleOpenIdConnect or a similar alternative backend if that's an easier solution. And while it seems to be closer to what the Google docs are talking about, I wasn't able to get it to work when I tried:
    • I get a 400 Error: invalid_request Parameter not allowed for this message type: nonce
    • I can get past the nonce error using social.backends.google.GoogleOpenIdConnect by adding id_token to the RESPONSE_TYPE but then I get an AuthMissingParameter error in my /complete/google-openidconnect/ endpoint as the request's GET and POST are empty. (Tried 'code id_token', 'token id_token', 'id_token', ...)
  • I don't want to use social.backends.google.GooglePlusAuth as that doesn't integrate as nicely with my current login form.
  • Worst case, I should be able to use social.pipeline.social_auth.associate_by_email, but I only have email addresses for maybe 80% of the users so that leaves quite a few who will have a new account and need support to associate it manually.

Try as I might, I can't find any examples of people doing a similar migration with python-social-auth, but it must be happening to lots of people.

Any ideas?


Source: (StackOverflow)

Get access token from Python Social Auth

I have Python Social Auth implemented on my site, and I'm trying to access (after the login process) into the access token that the user got. I can see on the Django admin that there's a field called extra_data containing the access token, but I don't know how to access it from my code.

Any idea?

I want to do something similar as it could be done in Django Social Auth: http://django-social-auth.readthedocs.org/en/latest/tokens.html


Source: (StackOverflow)

Are sessions needed for python-social-auth

I'm building a django app with an API backend(built with DRF) and angularjs client. My goal is to completely decouple the server and client using JWT in place of sessions. I'm attempting to integrate python-social-auth(PSA) with django-rest-framework-jwt(DRFJWT), so my goal is to have an auth flow something to this:

User logs with Email/facebook via angular client -> client posts form to PSA's url -> PSA login/create user ->[!] DRFJWT creates token that it then sends back to client -> client stores token in local storage then uses token each request

[!]: This is currently where I'm struggling. My thinking is that I can modify the do_complete method in PSA like so

from rest_framework_jwt.utils import jwt_payload_handler, jwt_encode_handler


def do_complete(backend, login, user=None, redirect_name='next',
            *args, **kwargs):
  # pop redirect value before the session is trashed on login()
  data = backend.strategy.request_data()
  redirect_value = backend.strategy.session_get(redirect_name, '') or \
                 data.get(redirect_name, '')

  is_authenticated = user_is_authenticated(user)
  user = is_authenticated and user or None

  partial = partial_pipeline_data(backend, user, *args, **kwargs)
  if partial:
      xargs, xkwargs = partial
      user = backend.continue_pipeline(*xargs, **xkwargs)
  else:
      user = backend.complete(user=user, *args, **kwargs)

  if user_is_active(user):
      # catch is_new/social_user in case login() resets the instance
      is_new = getattr(user, 'is_new', False)
      social_user = user.social_user
      login(backend, user, social_user)

  payload = jwt_payload_handler(user)
  return { 'token': jwt_encode_handler(payload) }

Is this the only way of doing what I'm trying to accomplish?

I'm also wondering if its okay from a best-practices standpoint to use sessions to manage the pipeline and JWT for auth?


Source: (StackOverflow)

python oauthlib: in escape ValueError "Only unicode objects are escapable"

I'm using python-social-auth to login with social networks from my Django application. On my local machine everything works fine, but when I deploy to a server I get the following error:

oauthlib.oauth1.rfc5849.utils in escape
ValueError: Only unicode objects are escapable. Got None of type <type 'NoneType'>.

Stacktrace:

File "django/core/handlers/base.py", line 112, in get_response
    response = wrapped_callback(request, *callback_args, **callback_kwargs)
File "social/apps/django_app/utils.py", line 45, in wrapper
    return func(request, backend, *args, **kwargs)
File "social/apps/django_app/views.py", line 12, in auth
    return do_auth(request.social_strategy, redirect_name=REDIRECT_FIELD_NAME)
File "social/actions.py", line 25, in do_auth
    return strategy.start()
File "social/strategies/base.py", line 66, in start
    return self.redirect(self.backend.auth_url())
File "social/backends/oauth.py", line 99, in auth_url
    token = self.set_unauthorized_token()
File "social/backends/oauth.py", line 158, in set_unauthorized_token
    token = self.unauthorized_token()
File "social/backends/oauth.py", line 177, in unauthorized_token
    method=self.REQUEST_TOKEN_METHOD)
File "social/backends/base.py", line 202, in request
    response = request(method, url, *args, **kwargs)
File "requests/api.py", line 44, in request
    return session.request(method=method, url=url, **kwargs)
File "requests/sessions.py", line 349, in request
    prep = self.prepare_request(req)
File "requests/sessions.py", line 287, in prepare_request
    hooks=merge_hooks(request.hooks, self.hooks),
File "requests/models.py", line 291, in prepare
    self.prepare_auth(auth, url)
File "requests/models.py", line 470, in prepare_auth
    r = auth(self)
File "requests_oauthlib/oauth1_auth.py", line 87, in __call__
    unicode(r.url), unicode(r.method), None, r.headers)
File "oauthlib/oauth1/rfc5849/__init__.py", line 293, in sign
    request.oauth_params.append(('oauth_signature', self.get_oauth_signature(request)))
File "oauthlib/oauth1/rfc5849/__init__.py", line 128, in get_oauth_signature
    uri, headers, body = self._render(request)
File "oauthlib/oauth1/rfc5849/__init__.py", line 199, in _render
    headers = parameters.prepare_headers(request.oauth_params, request.headers, realm=realm)
File "oauthlib/oauth1/rfc5849/utils.py", line 31, in wrapper
    return target(params, *args, **kwargs)
File "oauthlib/oauth1/rfc5849/parameters.py", line 57, in prepare_headers
    escaped_value = utils.escape(value)
File "oauthlib/oauth1/rfc5849/utilsy", line 56, in escape
    'Got %s of type %s.' % (u, type(u)))

Some packages from requirements.txt file:

Django==1.6.6
google-api-python-client==1.1
oauth2==1.5.211
oauthlib==0.6.3
python-openid==2.2.5
python-social-auth==0.1.26
requests==2.4.0
requests-oauthlib==0.4.1
six==1.7.3

Source: (StackOverflow)

python-social-auth partial pipeline can not resume

I am trying to collect the password for the new user with partial pipeline of python-social-auth. For some unknown reason, I am not able to resume the pipeline, the page render back to the password collection page after I submit the form.

What's wired is that even I typed the http.../complete/backend-name, the page will redirect back to the password collection page. It looks like the rendering goes into an endless loop, the password collection page first point to the complete page, the complete page direct back to the password collection page. I checked the value for REDIRECT_FIELD_NAME, it is "next".

I am not sure what's wrong with my code, any tips/suggestions are greatly appreciated.

settings.py

SOCIAL_AUTH_PIPELINE = (
    ...
    'accounts.pipeline.get_password',
    ...
)

pipeline.py

from django.shortcuts import redirect
from social.pipeline.partial import partial

@partial
def get_password(strategy, details, user=None, is_new=False, *args, **kwargs):
    if is_new:
        return redirect('accounts_signup_social')
    else:
        return

views.py

def get_password(request):
    if request.method == 'POST':
        request.session['password'] = request.POST.get('password')
        backend = request.session['partial_pipeline']['backend']
        return redirect('social:complete', backend=backend)
    return render_to_response('accounts/social_signup.html',{"form":SocialSignUpForm}, RequestContext(request))

Source: (StackOverflow)

python-social-auth backend not found for linkedin oauth2

I am trying to incorporate linkedin oauth2 in my app using python-social-auth. However, when i navigate to 127.0.0.1:8000/login/linkedin/ in Chrome I get a "Backend not found" error. Specifically, the logs display the following errors:

[08/Sep/2014 16:44:38] "GET /login/linkedin HTTP/1.1" 301 0
[08/Sep/2014 16:44:38] "GET /login/linkedin/ HTTP/1.1" 404 1608

I have the following related code in my settings.py:

INSTALLED_APPS = (
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',
    'github_app',
    'tech_seeker',
    'social.apps.django_app.default'
)

SOCIAL_AUTH_LINKEDIN_OAUTH2_KEY = "<MY_KEY_HERE>"
SOCIAL_AUTH_LINKEDIN_OAUTH2_SECRET = "<MY_SECRET_HERE>"

SOCIAL_AUTH_STRATEGY = 'social.strategies.django_strategy.DjangoStrategy'

AUTHENTICATION_BACKENDS = (
    'social.backends.linkedin.LinkedinOAuth2',
    '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',
    'github_app.auth_pipeline.user'
)

Any help is appreciated.


Source: (StackOverflow)