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
No, you do not need to use sessions(standard Django login system) with python-social-auth. What you need to make JWT and PSA work together is DRF.
Here's my solution:
I used standard PSA's url for making request too social /login/(?P
, changed url in urls.py to match redirect from Facebook/Twitter to my own.
url(r'^complete/(?P[^/]+)/$', views.SocialAuthViewComplete.as_view()),
The point of using API is to have access to user data in request that PSA is doing. DRF allow you to do it if you have JWT authentication in DEFAULT_AUTHENTICATION_CLASSES
REST_FRAMEWORK = {
'DEFAULT_AUTHENTICATION_CLASSES': (
'rest_framework.authentication.SessionAuthentication',
'rest_framework.authentication.TokenAuthentication',
'rest_framework_jwt.authentication.JSONWebTokenAuthentication',
),}
In views.py
from social.apps.django_app.views import complete
class SocialAuthViewComplete(APIView):
permission_classes = ()
def post(self, request, backend, *args, **kwargs):
try:
#Wrap up PSA's `complete` method.
authentication = complete(request, backend, *args, **kwargs)
except Exception, e:
exc = {
'error': str(e)
}
return Response(exc, status=status.HTTP_400_BAD_REQUEST)
return Response({'data': authentication}, status=status.HTTP_202_ACCEPTED)
Then I modified the do_complete
method in PSA:
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)
user_model = backend.strategy.storage.user.user_model()
if user and not isinstance(user, user_model):
return user
if is_authenticated:
if not user:
information = 'setting_url(backend, redirect_value, LOGIN_REDIRECT_URL'
else:
information = 'setting_url(backend, redirect_value, NEW_ASSOCIATION_REDIRECT_URL,LOGIN_REDIRECT_URL'
elif user:
# Get the JWT payload for the user.
payload = jwt_payload_handler(user)
if user_is_active(user):
is_new = getattr(user, 'is_new', False)
if is_new:
information = 'setting_url(backend, NEW_USER_REDIRECT_URL, redirect_value, LOGIN_REDIRECT_URL'
else:
information = 'setting_url(backend, redirect_value, LOGIN_REDIRECT_URL'
else:
return Response({
'status': 'Unauthorized',
'message': 'The user account is disabled.'
}, status=status.HTTP_401_UNAUTHORIZED)
else:
information = 'setting_url(backend, LOGIN_ERROR_URL, LOGIN_URL'
return { 'an information i may use in future': information,
'token': jwt_encode_handler(payload) # Create the response object with the JWT payload.
}
I tried pipelines and user association and it works correctly. Also you always can modify another method from PSA, if you need it to works with JWT.