social-auth-app-django: refresh access_token

  • Last Update :
  • Techknowledgy :

.get_access_token(strategy) refresh the token automatically if it's expired. You can use it like that:

from social_django.utils
import load_strategy
#...
   social = request.user.social_auth.get(provider = 'google-oauth2')
access_token = social.get_access_token(load_strategy())

Using load_strategy() at social.apps.django_app.utils:

social = request.user.social_auth.get(provider = 'azuread-oauth2')
strategy = load_strategy()
social.refresh_token(strategy)

The best approach is probably to check if it needs to be updated (customized for AzureAD Oauth2):

def get_azuread_oauth2_token(user):
   social = user.social_auth.get(provider = 'azuread-oauth2')
if social.extra_data['expires_on'] <= int(time.time()):
   strategy = load_strategy()
social.refresh_token(strategy)
return social.extra_data['access_token']

In future versions (>0.2.1 for the social-auth-core) there will be a new field in extra data:

'auth_time': int(time.time())

So now:

from social_django.utils
import load_strategy

social = request.user.social_auth.get(provider = 'azuread-oauth2')
response = self.get_json('https://graph.microsoft.com/v1.0/me',
      headers = {
         'Authorization': '%s %s' % (social.extra_data['token_type'],
            social.get_access_token(load_strategy())
         }

@NBajanca's update is almost correct for version 1.0.1.

extra_data['expires_in']

is now

extra_data['expires']

So the code is:

def get_token(user, provider):
   social = user.social_auth.get(provider = provider)
if (social.extra_data['auth_time'] + social.extra_data['expires']) <= int(time.time()):
   strategy = load_strategy()
social.refresh_token(strategy)
return social.extra_data['access_token']

Suggestion : 2

I use social-auth-app-django for my django website. Login all works, but after the token expires. I cant access the google’s user data anymore. I found how to refresh the token, but it gives,If the user already registered, you need to force the prompt first time (otherwhise you dont get the refresh token)

 File "/mnt/s/github/nascentapp/app/booking/management/commands/sendmail.py", line 17, in handle
 new_token = self.get_token(user = booking_user, provider = 'google-oauth2')
 File "/mnt/s/github/nascentapp/app/booking/management/commands/sendmail.py", line 28, in get_token
 social.refresh_token(strategy)
 File "/home/sander/.local/share/virtualenvs/app-YMrBBUv3/lib/python3.6/site-packages/social_core/storage.py", line 58, in refresh_token
 response = backend.refresh_token(token, * args, ** kwargs)
 File "/home/sander/.local/share/virtualenvs/app-YMrBBUv3/lib/python3.6/site-packages/social_core/backends/oauth.py", line 438, in refresh_token
 request = self.request(url, ** request_args)
 File "/home/sander/.local/share/virtualenvs/app-YMrBBUv3/lib/python3.6/site-packages/social_core/backends/base.py", line 234, in request
 response.raise_for_status()
 File "/home/sander/.local/share/virtualenvs/app-YMrBBUv3/lib/python3.6/site-packages/requests/models.py", line 941, in raise_for_status
 raise HTTPError(http_error_msg, response = self)
 requests.exceptions.HTTPError: 400 Client Error: Bad Request
 for url: https: //accounts.google.com/o/oauth2/token
def get_token(self, user, provider):
   social = user.social_auth.get(provider = provider)
print('This is social of user: ', social)
if (social.extra_data['auth_time'] + social.extra_data['expires']) <= int(time.time()):
   print('n Token is out of date n')
strategy = load_strategy()
social.refresh_token(strategy)
return social.extra_data['access_token']
AUTHENTICATION_BACKENDS = (
   'social_core.backends.open_id.OpenIdAuth', #
   for Google authentication 'social_core.backends.google.GoogleOpenId', #
   for Google authentication 'social_core.backends.google.GoogleOAuth2', #
   for Google authentication 'django.contrib.auth.backends.ModelBackend',
)

SOCIAL_AUTH_GOOGLE_OAUTH2_KEY = os.environ.get('DJANGO_SOCIAL_AUTH_GOOGLE_OAUTH2_KEY') # Paste CLient Key
SOCIAL_AUTH_GOOGLE_OAUTH2_SECRET = os.environ.get('DJANGO_SOCIAL_AUTH_GOOGLE_OAUTH2_SECRET') # Paste Secret Key

SOCIAL_AUTH_GOOGLE_OAUTH2_SCOPE = [
   'https://www.googleapis.com/auth/calendar.readonly',
   'https://www.googleapis.com/auth/calendar.events'
]
SOCIAL_AUTH_GOOGLE_OAUTH2_AUTH_EXTRA_ARGUMENTS = {
   'access_type': 'offline',
   'approval_prompt': 'auto'
}
/login/google - oauth2 ? approval_prompt = force

Suggestion : 3

Signup by OAuth access_token,Once we have the access token we can call the API like this:,Re-prompt Google OAuth2 users to refresh the refresh_token

<a href="{% url 'social:begin' 'facebook' %}?next={{ request.path }}">Login with Facebook</a>
SOCIAL_AUTH_FIELDS_STORED_IN_SESSION = ['key']
<a href="{% url 'social:begin' 'facebook' %}?key={{ value }}">Login with Facebook</a>
strategy.session_get('key')
SOCIAL_AUTH_GOOGLE_OAUTH2_SCOPE = [
   'https://www.googleapis.com/auth/plus.login'
]
import requests

user = User.objects.get(...)
social = user.social_auth.get(provider = 'google-oauth2')
response = requests.get(
   'https://www.googleapis.com/plus/v1/people/me/people/visible',
   params = {
      'access_token': social.extra_data['access_token']
   }
)
friends = response.json()['items']

Suggestion : 4

1 week ago I use social-auth-app-django for my django website. Login all works, but after the token expires. I cant access the google’s user data anymore. ,I use social-auth-app-django for my django website. Login all works, but after the token expires. I cant access the google's user data anymore. I found how to refresh the token, but it gives, 1 week ago Oct 16, 2012  · I have added offline access to my extra_arguments. Therefore Google returns a refresh token and it is stored by django-social-auth. The problem is that django-social-auth never uses this refresh token to update the access token. Therefore the access token expires after one hour, and I can't use it to perform offline requests. I want to keep the ... , 6 days ago social-auth-app-django Refresh access_token - Django [ Glasses to protect eyes while coding : https://amzn.to/3N1ISWI ] social-auth-app-django Refresh acces...


 File "/mnt/s/github/nascentapp/app/booking/management/commands/sendmail.py", line 17, in handle new_token = self.get_token(user = booking_user, provider = 'google-oauth2') File "/mnt/s/github/nascentapp/app/booking/management/commands/sendmail.py", line 28, in get_token social.refresh_token(strategy) File "/home/sander/.local/share/virtualenvs/app-YMrBBUv3/lib/python3.6/site-packages/social_core/storage.py", line 58, in refresh_token response = backend.refresh_token(token, * args, ** kwargs) File "/home/sander/.local/share/virtualenvs/app-YMrBBUv3/lib/python3.6/site-packages/social_core/backends/oauth.py", line 438, in refresh_token request = self.request(url, ** request_args) File "/home/sander/.local/share/virtualenvs/app-YMrBBUv3/lib/python3.6/site-packages/social_core/backends/base.py", line 234, in request response.raise_for_status() File "/home/sander/.local/share/virtualenvs/app-YMrBBUv3/lib/python3.6/site-packages/requests/models.py", line 941, in raise_for_status raise HTTPError(http_error_msg, response = self) requests.exceptions.HTTPError: 400 Client Error: Bad Request
 for url: https: //accounts.google.com/o/oauth2/token 

SOCIAL_AUTH_GOOGLE_OAUTH2_AUTH_EXTRA_ARGUMENTS = {
   'access_type': 'offline',
   'approval_prompt': 'auto'
}

Suggestion : 5

Now the updated access_token can be retrieved from social.extra_data['access_token'].,The best approach is probably to check if it needs to be updated (customized for AzureAD Oauth2):,Following an Issue to request an extra data parameter with the time of the access token refresh, it is now possible to check if the access_token needs to be updated in every backend.,I'd also recommend subtracting an arbitrary amount of time from that calc, so that we don't run into a race situation where we've checked the token 0.01s before expiry and then get an error because we sent the request after expiry. I like to add 10 seconds just to be safe, but it's probably overkill:

Using load_strategy() at social.apps.django_app.utils:

social = request.user.social_auth.get(provider = 'azuread-oauth2')
strategy = load_strategy()
social.refresh_token(strategy)

The best approach is probably to check if it needs to be updated (customized for AzureAD Oauth2):

def get_azuread_oauth2_token(user):
   social = user.social_auth.get(provider = 'azuread-oauth2')
if social.extra_data['expires_on'] <= int(time.time()):
   strategy = load_strategy()
social.refresh_token(strategy)
return social.extra_data['access_token']

In future versions (>0.2.1 for the social-auth-core) there will be a new field in extra data:

'auth_time': int(time.time())

So now:

from social_django.utils
import load_strategy

social = request.user.social_auth.get(provider = 'azuread-oauth2')
response = self.get_json('https://graph.microsoft.com/v1.0/me',
      headers = {
         'Authorization': '%s %s' % (social.extra_data['token_type'],
            social.get_access_token(load_strategy())
         }

@NBajanca's update is almost correct for version 1.0.1.

extra_data['expires_in']

is now

extra_data['expires']

So the code is:

def get_token(user, provider):
   social = user.social_auth.get(provider = provider)
if (social.extra_data['auth_time'] + social.extra_data['expires']) <= int(time.time()):
   strategy = load_strategy()
social.refresh_token(strategy)
return social.extra_data['access_token']

.get_access_token(strategy) refresh the token automatically if it's expired. You can use it like that:

from social_django.utils
import load_strategy
#...
   social = request.user.social_auth.get(provider = 'google-oauth2')
access_token = social.get_access_token(load_strategy())

Suggestion : 6

In this tutorial, you’ll learn how to integrate OAuth 2 into your Django or Django Rest Framework using Python Social Auth. Although this article focuses on the Django REST Framework, you can apply the information provided here to implement the same in a variety of other common back-end frameworks.,For example, Google includes a refresh token that extends the life of your access token while Facebook provides an endpoint at which you can exchange short-lived access tokens for something longer-lived. These details don’t matter to us, though, because we’re not going to use this flow.,Allowing the front-end to handle the access token is an expedient technique that retains the separation of concerns. It somewhat increases the risk from a compromised client, but it works well, in general.,So you’ve implemented user authentication. Now, you want to allow your users to log in with Twitter, Facebook, or Google. No problem. You’re only a few lines of code away from doing so. But while there are hundreds of OAuth 2 packages that pip knows, only a few actually do what they’re supposed to do. In this article, Toptal Software Engineer Peter Goodspeed-Niklaus explains how to integrate OAuth 2 into your Django or Django Rest Framework using Python Social Auth.

The flow begins when your application generates a page that includes a button, like “Log in with Facebook” or “Sign in with Google+”. Fundamentally, these are nothing other than simple links, each of which points to a URL like the following:

https: //oauth2provider.com/auth?
   response_type = code &
   client_id = CLIENT_KEY &
   redirect_uri = CALLBACK_URI &
   scope = profile &
   scope = email

The authorization code is a fast-expiring, single-use token; immediately upon its receipt, your server should turn around, and make another request to the OAuth 2 provider, including both the authorization code and your client secret:

POST https: //oauth2provider.com/token/?
   grant_type = authorization_code &
   code = AUTH_CODE &
   redirect_uri = CALLBACK_URI &
   client_id = CLIENT_KEY &
   client_secret = CLIENT_SECRET

The URL looks a little different this time though:

https: //oauth2provider.com/auth?
   response_type = token &
   client_id = CLIENT_KEY &
   redirect_uri = CALLBACK_URI &
   scope = profile &
   scope = email

There’s just a little more that needs to go in your settings (full code), and then you’re all set:

AUTHENTICATION_BACKENDS = (
   'social_core.backends.google.GoogleOAuth2',
   'social_core.backends.facebook.FacebookOAuth2',
   'django.contrib.auth.backends.ModelBackend',
)
for key in ['GOOGLE_OAUTH2_KEY',
      'GOOGLE_OAUTH2_SECRET',
      'FACEBOOK_KEY',
      'FACEBOOK_SECRET'
   ]:
   # Use exec instead of eval here because we 're not just trying to evaluate a dynamic value here;
# we 're setting a module attribute whose name varies.
exec("SOCIAL_AUTH_{key} = os.environ.get('{key}')".format(key = key))
SOCIAL_AUTH_PIPELINE = (
   'social_core.pipeline.social_auth.social_details',
   'social_core.pipeline.social_auth.social_uid',
   'social_core.pipeline.social_auth.auth_allowed',
   'social_core.pipeline.social_auth.social_user',
   'social_core.pipeline.user.get_username',
   'social_core.pipeline.social_auth.associate_by_email',
   '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',
)

Suggestion : 7

The rest_framework.authtoken app provides Django database migrations.,For details on configuration and usage see the Django REST framework OAuth documentation for authentication and permissions.,This library provides a set of REST API endpoints for registration, authentication (including social media authentication), password reset, retrieve and update user details, etc. By having these API endpoints, your client apps such as AngularJS, iOS, Android, and others can communicate to your Django backend site independently via REST APIs for user management.,This authentication scheme uses HTTP Basic Authentication, signed against a user's username and password. Basic authentication is generally only appropriate for testing.

The default authentication schemes may be set globally, using the DEFAULT_AUTHENTICATION_CLASSES setting. For example.

REST_FRAMEWORK = {
   'DEFAULT_AUTHENTICATION_CLASSES': [
      'rest_framework.authentication.BasicAuthentication',
      'rest_framework.authentication.SessionAuthentication',
   ]
}

You can also set the authentication scheme on a per-view or per-viewset basis, using the APIView class-based views.

from rest_framework.authentication
import SessionAuthentication, BasicAuthentication
from rest_framework.permissions
import IsAuthenticated
from rest_framework.response
import Response
from rest_framework.views
import APIView

class ExampleView(APIView):
   authentication_classes = [SessionAuthentication, BasicAuthentication]
permission_classes = [IsAuthenticated]

def get(self, request, format = None):
   content = {
      'user': str(request.user),
      # `django.contrib.auth.User`
      instance.
      'auth': str(request.auth),
      # None
   }
return Response(content)

Or, if you're using the @api_view decorator with function based views.

@api_view(['GET'])
@authentication_classes([SessionAuthentication, BasicAuthentication])
@permission_classes([IsAuthenticated])
def example_view(request, format = None):
   content = {
      'user': str(request.user),
      # `django.contrib.auth.User`
      instance.
      'auth': str(request.auth),
      # None
   }
return Response(content)

Unauthenticated responses that are denied permission will result in an HTTP 401 Unauthorized response with an appropriate WWW-Authenticate header. For example:

WWW - Authenticate: Basic realm = "api"

To use the TokenAuthentication scheme you'll need to configure the authentication classes to include TokenAuthentication, and additionally include rest_framework.authtoken in your INSTALLED_APPS setting:

INSTALLED_APPS = [
   ...
   'rest_framework.authtoken'
]