最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

python - How to use django-allauth for Google API? - Stack Overflow

programmeradmin2浏览0评论

How is django-allauth implemented to obtain authorization using Oauth2 for a Google API (in my case the Gmail API)? Additionally, I am looking to implement this separately from using django-allauth to have users log in with Google, so I would need to store it separately, and also call it in a view.

Thanks!

How is django-allauth implemented to obtain authorization using Oauth2 for a Google API (in my case the Gmail API)? Additionally, I am looking to implement this separately from using django-allauth to have users log in with Google, so I would need to store it separately, and also call it in a view.

Thanks!

Share Improve this question asked Feb 6 at 20:34 Kovy JacobKovy Jacob 1,0278 silver badges24 bronze badges
Add a comment  | 

1 Answer 1

Reset to default 1

I'm assuming you have already followed this document and this, and made all the necessary primary settings.

Then you can use django-allauth to set up authentication via Google, with tokens saved. Specify the required parameters for gmail scope. Then use these tokens to work with GmailAPI.

First you need to set some settings, this is described in this document (SOCIALACCOUNT_STORE_TOKENS constant). Something like this:

#  settings.py
SOCIALACCOUNT_STORE_TOKENS = True
SOCIALACCOUNT_EMAIL_AUTHENTICATION = True
SOCIALACCOUNT_EMAIL_AUTHENTICATION_AUTO_CONNECT = True

Also configure “access_type”: “offline”, in the google provider settings, as described here:

You must set AUTH_PARAMS['access_type'] to offline in order to receive a refresh token on first login and on reauthentication requests (which is needed to refresh authentication tokens in the background, without involving the user’s browser). When unspecified, Google defaults to online.

Now, after the user logs in to your system through google account, a database entry will be created with his access_token and refresh_token (token_secret in db_table). You can check this in the admin interface in this table:

To use GmailAPI, you need the google user ID and its access_token, this can be found like this:

def get_user_google_tokens(request: HttpRequest, limit: int = 1) -> list[dict]:
    from allauth.socialaccount.models import SocialToken
    from django.db import models

    user_google_tokens = list(
        SocialToken.objects
        .filter(account__provider='google', account__user_id=request.user.pk)
        .annotate(google_user_id=models.F('account__uid'))
        .order_by('-expires_at')
        .values('token', 'token_secret', 'expires_at', 'google_user_id')[:limit]
    )
    print(user_google_tokens)
    #  [
    #   {'token': '...', 
    #    'token_secret': '...', 
    #    'expires_at': datetime.datetime(2025, 2, 7, 16, 38, 16, 611588, tzinfo=datetime.timezone.utc), 
    #    'google_user_id': '...'}
    #  ]
    return user_google_tokens

Note that access_token has a short validity of one hour, by default. You can read more about it here. When your access_token expires in time, you will need to refresh it using refresh_token (token_secret), and write new access_token to the database by modifying an existing entry. Here's an example of how to refresh. Also note that sometimes you will not be able to refresh tokens using refresh_token.

Here is an example of a request to update a token using Postman. But you will probably use some library for http requests for python. Or some off-the-shelf client, for that matter. django-allauth doesn't seem to be able to update tokens, but I don't know for sure, I haven't checked that.

UPDATED

The answer to your question from the comments. Yes, you can use two google social applications, with different client_id, and different settings, but you would then need to use a custom DefaultSocialAccountAdapter, and your own views to specify which config should be used. There may be a simpler option, but this is the first one I tried and it works.

There is also a much simpler option, you can have one configuration for the google provider, but you can set dynamically the parameters to be used, for example scope and access_type.

Here's an example, you have a google login endpoint, let's say it's the default google_login endpoint in django-allauth. So you also have one config set up for the google provider. By default, you don't need to ask the user for permission to use their gmail, in which case they just log in. Then, the user wants to use your functions that work with GmailAPI, you ask them to authenticate again and provide additional permissions. In django-allauth, these dynamic parameters can be passed using GET parameters. Here's an example of how to do this using HTML exclusively. You'll probably have this in different files, but here is the gist of how it's done:

{#Google Gmail Login Form#}  
<form method="POST" action="{% url 'google_login' %}?scope=https://mail.google.com/&auth_params=access_type=offline">  
  {% csrf_token %}  
  <button type="submit">GOOGLE GMAIL</button>  
</form>  
  
{#Google Base Login Form#}  
<form method="POST" action="{% url 'google_login' %}">  
  {% csrf_token %}  
  <button type="submit">GOOGLE</button>  
</form>

Here's my basic google config in settings:

SOCIALACCOUNT_PROVIDERS = {
    'google': {
        'APP': {
            'client_id': '.....',
            'secret': '.....',
            'key': '.....',
            'settings': {
                'scope': [
                    'profile',
                    'email',
                ],
                'auth_params': {
                    'access_type': 'online',
                    # it is important to leave it so that the `google`  
                    # confirmation window is always displayed.                        
                    'prompt': 'consent',
                },
                'oauth_pkce_enabled': True,
            },
        },
        'FETCH_USER_INFO': True,
    },
}

The point is that when a user logs in via google, the refresh_token is not saved, but when logging in to google, with additional parameters - ?scope=https://mail.google.com/&auth_params=access_type=offline it will be saved in the database. In this way it will be possible to understand if the user has permissions to use GmailAPI:

user_google_tokens = list(  
    SocialToken.objects  
    .filter(account__provider='google', account__user_id=some_user.id) 
    .exclude(token_secret='')  
    .annotate(google_user_id=models.F('account__uid'))  
    .order_by('-expires_at')  
    .values('token', 'token_secret', 'expires_at', 'google_user_id')[:1]  
)

Here is an example method to handle dynamically passed auth_params, from GET request parameters. You can also check out the other methods to learn more.

发布评论

评论列表(0)

  1. 暂无评论