AuthAlreadyAssociated Exception in Django Social Auth
DSA doesn't logout accounts (or flush sessions) at the moment. AuthAlreadyAssociated
highlights the scenario where the current user is not associated to the current social account trying to be used. There are a couple solutions that might suite your project:
Define a sub-class of
social_auth.middleware.SocialAuthExceptionMiddleware
and override the default behavior (process_exception()
) to redirect or setup the warning you like in the way you prefer.Add a pipeline method (replacing
social_auth.backend.pipeline.social.social_auth_user
) that logouts the current user instead of raising an exception.
Solution for people wondering how to override social_user pipeline under python-social-auth version 3+
In your 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', # Path to your overrided method # You can set any other valid path. 'myproject.apps.python-social-auth-overrided.pipeline.social_auth.social_user', 'social_core.pipeline.user.get_username', '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',)
In your overrided social_user:
from django.contrib.auth import logoutdef social_user(backend, uid, user=None, *args, **kwargs): provider = backend.name social = backend.strategy.storage.user.get_social_auth(provider, uid) if social: if user and social.user != user: logout(backend.strategy.request) elif not user: user = social.user return {'social': social, 'user': user, 'is_new': user is None, 'new_association': False}
You can delete commented lines if you want.
My approach to this problem was a little different, instead of tackling this in the pipeline, I made sure that a user was never passed into the pipeline in the first place. This way, even if the social_auth.user does not match the logged in user, the social_auth.user will be logged in on top of the currently logged in user.
I think it's as easy as overriding the complete
action.
urls.py
url(r'^complete/(?P<backend>[^/]+)/$', 'account.views.complete', name='complete'),
account/views.py
from social.actions import do_completefrom social.apps.django_app.utils import strategyfrom social.apps.django_app.views import _do_login@csrf_exempt@strategy('social:complete')def complete(request, backend, *args, **kwargs): """Override this method so we can force user to be logged out.""" return do_complete(request.social_strategy, _do_login, user=None, redirect_name=REDIRECT_FIELD_NAME, *args, **kwargs)