Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Google login in django rest framework + allauth + rest-auth

I'm trying to implement Google authentication in django with allauth and rest-auth. After many hours of research, none of the solutions I found worked in my project.

I based my code on a github issue: https://github.com/Tivix/django-rest-auth/issues/403

And an article: https://medium.com/@gonzafirewall/google-oauth2-and-django-rest-auth-92b0d8f70575

I have also created a Social Application object with Google client id and client secret

My project setup in google console:

Authorized JavaScript origins: http://localhost:8000 Authorized redirect URIs: http://localhost:8000/api/v1/users/login/google/callback/

My code

providers.py:

from allauth.socialaccount.providers.google.provider import GoogleProvider


class GoogleProviderMod(GoogleProvider):
    def extract_uid(self, data):
        return str(data['sub'])

adapters.py:

from allauth.socialaccount.providers.google.views import GoogleOAuth2Adapter
from google.auth.transport import requests
from google.oauth2 import id_token

from myproj.users.providers import GoogleProviderMod


class GoogleOAuth2AdapterIdToken(GoogleOAuth2Adapter):
    provider_id = GoogleProviderMod.id

    def complete_login(self, request, app, token, **kwargs):
        idinfo = id_token.verify_oauth2_token(token.token, requests.Request(), app.client_id)
        if idinfo["iss"] not in ["accounts.google.com", "https://accounts.google.com"]:
            raise ValueError("Wrong issuer.")
        extra_data = idinfo
        login = self.get_provider().sociallogin_from_response(request, extra_data)
        return login

views.py:

from allauth.socialaccount.providers.oauth2.client import OAuth2Client
from rest_auth.registration.serializers import SocialLoginSerializer
from rest_auth.registration.views import SocialLoginView

from myproj.users.adapters import GoogleOAuth2AdapterIdToken


class GoogleLoginView(SocialLoginView):
    adapter_class = GoogleOAuth2AdapterIdToken
    callback_url = "http://localhost:8000/api/v1/users/login/google/callback/"
    client_class = OAuth2Client
    serializer_class = SocialLoginSerializer

urls.py:

from allauth.socialaccount.providers.oauth2.views import OAuth2CallbackView
from django.urls import path

from myproj.users.adapters import GoogleOAuth2AdapterIdToken
from myproj.users.views import GoogleLoginView

app_name = "users"
urlpatterns = [
    path(
        "login/google/",
        GoogleLoginView.as_view(),
        name="google_login"
    ),
    path(
        "login/google/callback/",
        OAuth2CallbackView.adapter_view(GoogleOAuth2AdapterIdToken),
        name="google_callback"
    ),
]

settings.py:

AUTHENTICATION_BACKENDS = [
    "django.contrib.auth.backends.ModelBackend",
    "allauth.account.auth_backends.AuthenticationBackend",
]
ACCOUNT_DEFAULT_HTTP_PROTOCOL = "http"

When I passing ID Token (returned from Google 'sign in' button) as code parameter on login page, the error occurring:

allauth.socialaccount.providers.oauth2.client.OAuth2Error: Error retrieving access token: b'{\n "error": "invalid_grant",\n "error_description": "Malformed auth code."\n}' Response code is 400.

Actually, even if I passing some random text to the code, the error is the same.

Thanks for help!

like image 594
PolishCoder Avatar asked Jul 29 '19 10:07

PolishCoder


People also ask

Which authentication is best in Django REST framework?

And these are all provided by drf(django rest framework) and other than these like oauth, oauth2 based authentication are provided by the efforts of the community with help of other python packages. And they can be easily used in the production environment.

What is Allauth in Django?

Integrated set of Django applications addressing authentication, registration, account management as well as 3rd party (social) account authentication.


1 Answers

I also integrate djangorestframework + django-allauth + django-rest-auth + djangorestframework-jwt. But, I just implement for Signin with Google, so user can't register manual.

Here is my code:

views.py

from allauth.socialaccount.providers.google.views import GoogleOAuth2Adapter
from allauth.socialaccount.providers.oauth2.client import OAuth2Client
from rest_auth.registration.views import SocialLoginView


class GoogleLogin(SocialLoginView):
    adapter_class = GoogleOAuth2Adapter
    client_class = OAuth2Client

urls.py

...
path('auth/google', GoogleLogin.as_view(), name='google_login'),
...

settings.py

INSTALLED_APPS = [
    ...
    'allauth',
    'allauth.account',
    'allauth.socialaccount',
    'allauth.socialaccount.providers.google',
    ...
]
SITE_ID = 1
REST_USE_JWT = True    # this is for djangorestframework-jwt

[UPDATE]
To use code params on SocialLoginView endpoint:

  • create redirect uri that accessible (I think it's on frontend, or you can use simple view)
  • use https callback (I use ngrok to do it in my local development)
  • access the url directly (dont use google oauth playgroud to get code, because the client_id is different) or just copy the request url on oauth palygroud and change the redirect_uri and cliend_id. here is the link https://accounts.google.com/o/oauth2/v2/auth?redirect_uri=<https_callback>&prompt=consent&response_type=code&client_id=<cliend_id>&scope=email&access_type=offline
like image 152
aijogja Avatar answered Sep 17 '22 05:09

aijogja