iMerica / dj-rest-auth

Authentication for Django Rest Framework
https://dj-rest-auth.readthedocs.io/en/latest/index.html
MIT License
1.63k stars 304 forks source link

Invalid id_token error for google login #490

Open learningnoobi opened 1 year ago

learningnoobi commented 1 year ago

I am getting this annoying error during oauth with google login

My adapther code is :

class GoogleLogin(SocialLoginView):
    adapter_class = GoogleOAuth2Adapter
    client_class = OAuth2Client
    callback_url = "http://127.0.0.1:8000/accounts/google/login/callback/"

config:


REST_AUTH = {
    "JWT_AUTH_REFRESH_COOKIE": "refresh",
    "SESSION_LOGIN": True,
    "USE_JWT": True,
    "JWT_AUTH_COOKIE": "jwt-auth",
    "USER_DETAILS_SERIALIZER": "users.serializers.UserSerializer",
    "JWT_SERIALIZER": "users.serializers.JWTCustomSerializer",
    "TOKEN_MODEL": None,
}

and I am getting this error :

   File "/home/appuser/.local/lib/python3.8/site-packages/allauth/socialaccount/providers/google/views.py", line 39, in complete_login 
    raise OAuth2Error("Invalid id_token") from e
  allauth.socialaccount.providers.oauth2.client.OAuth2Error: Invalid id_token
  ERROR "POST /dj-rest-auth/google/ HTTP/1.1" 500 184636

This used to work but now it doesn't. Is it because of some policy change from google side or I am doing something wrong ?

learningnoobi commented 1 year ago

This solution worked for me:

from allauth.socialaccount.providers.google.views import GoogleOAuth2Adapter
from allauth.socialaccount.providers.oauth2.client import OAuth2Error

class CustomGoogleOAuth2Adapter(GoogleOAuth2Adapter):
    def complete_login(self, request, app, token, response, **kwargs):
        try:
            print("Response : ",response["id_token"])
            identity_data = jwt.decode(
                response["id_token"]["id_token"], #another nested id_token was returned
                options={
                    "verify_signature": False,
                    "verify_iss": True,
                    "verify_aud": True,
                    "verify_exp": True,
                },
                issuer=self.id_token_issuer,
                audience=app.client_id,
            )
        except jwt.PyJWTError as e:
            raise OAuth2Error("Invalid id_token") from e
        login = self.get_provider().sociallogin_from_response(request, identity_data)
        return login

class GoogleLogin(SocialLoginView):
    adapter_class = CustomGoogleOAuth2Adapter
    client_class = OAuth2Client
    callback_url = "http://127.0.0.1:8000/accounts/google/login/callback/"
Tiagura commented 1 year ago

did you enable JSON Web Token (JWT) for this? I don't need/want to use it. I get the same error and don't know how to resolve it

learningnoobi commented 1 year ago

did you enable JSON Web Token (JWT) for this? I don't need/want to use it. I get the same error and don't know how to resolve it

Yes I did I resolved it by overriding GoogleOauthprovider like I did above.

suhjohn commented 1 year ago

Have a fix in allauth here https://github.com/pennersr/django-allauth/pull/3278 please comment like and subscribe

AxanIqbal commented 1 year ago

still having this kind of issue in v3.0.0

class CustomGoogleOAuth2Adapter(GoogleOAuth2Adapter):
    def complete_login(self, request, app, token, response, **kwargs):
        id_token = response["id_token"]
        print(id_token)
        if type(id_token) is dict:
            id_token = id_token["id_token"]
        response["id_token"] = id_token
        print(response["id_token"])
        return super().complete_login(request, app, token, response, **kwargs)

class GoogleLogin(
    SocialLoginView
): 
    adapter_class = CustomGoogleOAuth2Adapter
    callback_url = "https://***/accounts/google/login/callback/"
    client_class = OAuth2Client
Traceback (most recent call last):
File "/usr/local/lib/python3.10/site-packages/jwt/api_jws.py", line 251, in _load
     header_segment, payload_segment = signing_input.split(b".", 1)
ValueError: not enough values to unpack (expected 2, got 1)

Traceback (most recent call last):
File "/usr/local/lib/python3.10/site-packages/asgiref/sync.py", line 486, in thread_handler
  raise exc_info[1]
File "/usr/local/lib/python3.10/site-packages/django/core/handlers/exception.py", line 43, in inner
  response = await get_response(request)
File "/usr/local/lib/python3.10/site-packages/django/core/handlers/base.py", line 253, in _get_response_async
  response = await wrapped_callback(
File "/usr/local/lib/python3.10/site-packages/asgiref/sync.py", line 448, in __call__
  ret = await asyncio.wait_for(future, timeout=None)
File "/usr/local/lib/python3.10/asyncio/tasks.py", line 408, in wait_for
  return await fut
File "/usr/local/lib/python3.10/site-packages/asgiref/current_thread_executor.py", line 22, in run
  result = self.fn(*self.args, **self.kwargs)
File "/usr/local/lib/python3.10/site-packages/asgiref/sync.py", line 490, in thread_handler
  return func(*args, **kwargs)
File "/usr/local/lib/python3.10/contextlib.py", line 79, in inner
  return func(*args, **kwds)
File "/usr/local/lib/python3.10/site-packages/django/views/decorators/csrf.py", line 55, in wrapped_view
  return view_func(*args, **kwargs)
File "/usr/local/lib/python3.10/site-packages/django/views/generic/base.py", line 84, in view
  return self.dispatch(request, *args, **kwargs)
File "/usr/local/lib/python3.10/site-packages/django/utils/decorators.py", line 46, in _wrapper
  return bound_method(*args, **kwargs)
File "/usr/local/lib/python3.10/site-packages/django/views/decorators/debug.py", line 92, in sensitive_post_parameters_wrapper
  return view(request, *args, **kwargs)
File "/usr/local/lib/python3.10/site-packages/dj_rest_auth/views.py", line 48, in dispatch
  return super().dispatch(*args, **kwargs)
File "/usr/local/lib/python3.10/site-packages/rest_framework/views.py", line 509, in dispatch
  response = self.handle_exception(exc)
File "/usr/local/lib/python3.10/site-packages/rest_framework/views.py", line 469, in handle_exception
  self.raise_uncaught_exception(exc)
File "/usr/local/lib/python3.10/site-packages/rest_framework/views.py", line 480, in raise_uncaught_exception
  raise exc
File "/usr/local/lib/python3.10/site-packages/rest_framework/views.py", line 506, in dispatch
  response = handler(request, *args, **kwargs)
File "/usr/local/lib/python3.10/site-packages/dj_rest_auth/views.py", line 125, in post
  self.serializer.is_valid(raise_exception=True)
File "/usr/local/lib/python3.10/site-packages/rest_framework/serializers.py", line 227, in is_valid
  self._validated_data = self.run_validation(self.initial_data)
File "/usr/local/lib/python3.10/site-packages/rest_framework/serializers.py", line 429, in run_validation
  value = self.validate(value)
File "/usr/local/lib/python3.10/site-packages/dj_rest_auth/registration/serializers.py", line 151, in validate
  login = self.get_social_login(adapter, app, social_token, response={'id_token': token})
File "/usr/local/lib/python3.10/site-packages/dj_rest_auth/registration/serializers.py", line 60, in get_social_login
  social_login = adapter.complete_login(request, app, token, response=response)
File "/app/config/adapters.py", line 18, in complete_login
  return super().complete_login(request, app, token, response, **kwargs)
File "/usr/local/lib/python3.10/site-packages/allauth/socialaccount/providers/google/views.py", line 39, in complete_login
  raise OAuth2Error("Invalid id_token") from e
2023-03-25T11:35:33.475281621Z allauth.socialaccount.providers.oauth2.client.OAuth2Error: Invalid id_token
2023-03-25T11:35:34.875371873Z INFO:     172.21.0.1:38540 - "POST /api/auth/login/google/ HTTP/1.1" 500 Internal Server Error
Michal99Zajac commented 1 year ago

I printed id_token and noticed that in the place of id_token i have access_token. So I swapped those values in place and everything started working.

Michal99Zajac commented 1 year ago

After deeper investigation I discovered that id_token in the form is not needed, and the basic configuration given in the documentation is correct. Only need to remember to specify id_token in place of access_token. Summarizing to code, it is enough:

views.py

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

urls.py

urlpatterns = [
    ...
    path("accounts/", include("allauth.urls")),
    path("auth/", include("dj_rest_auth.urls")),
    path("auth/google/", GoogleLogin.as_view(), name="google login"),
    ...
]

settings.py

SOCIALACCOUNT_PROVIDERS = {
    "google": {
        "APP": {
            "client_id": env("OAUTH_GOOGLE_CLIENT_ID"),
            "secret": env("OAUTH_GOOGLE_SECRET"),
            "key": "",
        },
        "SCOPE": [
            "profile",
            "email",
        ],
        "AUTH_PARAMS": {
            "access_type": "offline",
        },
    }
}