Search code examples
pythondjangogoogle-oauthpython-social-auth

How to refresh Google OAuth2 token programatically


I'm using Django with python-social-auth to authenticate my users with Google OAuth2 and use the Youtube API.

What I would like to achieve is ask them to login and authorize only once and be able to use their credentials as long as I want. This is not possible because after about an hour they expire and I need the user to re-authorize my application to get new credentials.

I assume the solution is to refresh the credentials periodically but I could not find any reliable guide in how to do this.

My current configuration is:

SOCIAL_AUTH_GOOGLE_OAUTH2_KEY = 'the_key'
SOCIAL_AUTH_GOOGLE_OAUTH2_SECRET = 'the_secret'
SOCIAL_AUTH_GOOGLE_OAUTH2_SCOPE = ["https://www.googleapis.com/auth/youtube.readonly", "https://www.googleapis.com/auth/yt-analytics.readonly"]
SOCIAL_AUTH_GOOGLE_OAUTH2_AUTH_EXTRA_ARGUMENTS = {
   'access_type': 'offline',
   'approval_prompt': 'force'
}

Also, an authorized user has the following extras:

{
  "access_token": "the_access_token",
  "expires": 3600,
  "refresh_token": "the_refresh_token",
  "token_type": "Bearer"
}

I've tried refreshing it with the code below but since It still expires I think it is not the correct way:

social_user = UserSocialAuth.objects.get(...)  # Fetch the instance
social_user.refresh_token(load_strategy())  # Returns "None"

Solution

  • After some more tests I found out that using refresh_token actually does refresh it for another hour of usage, so what I need to do is have a cron job to run a Django command to refresh them before expiration, something like below:

    # app/management/commands/refresh_token_youtube.py    
    
    from django.core.management.base import BaseCommand
    from social.apps.django_app.me.models import UserSocialAuth
    from social.apps.django_app.utils import load_strategy
    
    
    class Command(BaseCommand):
        def handle(self, *args, **options):
            for social_user in UserSocialAuth.objects.filter(provider='google-oauth2'):
                social_user.refresh_token(load_strategy())
    
    # crontab to run it every 30th minute
    
    */30 * * * * /path_to/env/bin/python /path_to/refresh_token_youtube.py
    

    What I really wanted though is a way to be able to refresh/have the token on demand like other social networks provide (Instagram, Twitter, Facebook) that only need one sign in and the credentials never expire.