iMerica / dj-rest-auth

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

Fix Google login with auth code flow #488

Closed c-w closed 1 year ago

c-w commented 1 year ago

In https://github.com/iMerica/dj-rest-auth/pull/482 a regression was introduced for logging in with Google using the auth-code flow:

Traceback (most recent call last):
  File "/venv/lib/python3.11/site-packages/allauth/socialaccount/providers/google/views.py", line 21, in complete_login
    identity_data = jwt.decode(
                    ^^^^^^^^^^^
  File "/venv/lib/python3.11/site-packages/jwt/api_jwt.py", line 168, in decode
    decoded = self.decode_complete(
              ^^^^^^^^^^^^^^^^^^^^^
  File "/venv/lib/python3.11/site-packages/jwt/api_jwt.py", line 120, in decode_complete
    decoded = api_jws.decode_complete(
              ^^^^^^^^^^^^^^^^^^^^^^^^
  File "/venv/lib/python3.11/site-packages/jwt/api_jws.py", line 191, in decode_complete
    payload, signing_input, header, signature = self._load(jwt)
                                                ^^^^^^^^^^^^^^^
  File "/venv/lib/python3.11/site-packages/jwt/api_jws.py", line 247, in _load
    raise DecodeError(f"Invalid token type. Token must be a {bytes}")
jwt.exceptions.DecodeError: Invalid token type. Token must be a <class 'bytes'>

The above exception was the direct cause of the following exception:

Traceback (most recent call last):
  File "/opt/project/backend/profiles/tests.py", line 209, in test_social_login_google
    response = self.client.post(
               ^^^^^^^^^^^^^^^^^
  File "/venv/lib/python3.11/site-packages/django/test/client.py", line 852, in post
    response = super().post(
               ^^^^^^^^^^^^^
  File "/venv/lib/python3.11/site-packages/django/test/client.py", line 441, in post
    return self.generic(
           ^^^^^^^^^^^^^
  File "/venv/lib/python3.11/site-packages/django/test/client.py", line 541, in generic
    return self.request(**r)
           ^^^^^^^^^^^^^^^^^
  File "/venv/lib/python3.11/site-packages/django/test/client.py", line 810, in request
    self.check_exception(response)
  File "/venv/lib/python3.11/site-packages/django/test/client.py", line 663, in check_exception
    raise exc_value
  File "/venv/lib/python3.11/site-packages/django/core/handlers/exception.py", line 56, in inner
    response = get_response(request)
               ^^^^^^^^^^^^^^^^^^^^^
  File "/venv/lib/python3.11/site-packages/django/core/handlers/base.py", line 197, in _get_response
    response = wrapped_callback(request, *callback_args, **callback_kwargs)
               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/venv/lib/python3.11/site-packages/django/views/decorators/csrf.py", line 55, in wrapped_view
    return view_func(*args, **kwargs)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/venv/lib/python3.11/site-packages/django/views/generic/base.py", line 103, in view
    return self.dispatch(request, *args, **kwargs)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/venv/lib/python3.11/site-packages/rest_framework/views.py", line 509, in dispatch
    response = self.handle_exception(exc)
               ^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/venv/lib/python3.11/site-packages/rest_framework/views.py", line 469, in handle_exception
    self.raise_uncaught_exception(exc)
  File "/venv/lib/python3.11/site-packages/rest_framework/views.py", line 480, in raise_uncaught_exception
    raise exc
  File "/venv/lib/python3.11/site-packages/rest_framework/views.py", line 506, in dispatch
    response = handler(request, *args, **kwargs)
               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/opt/project/backend/profiles/views.py", line 147, in post
    serializer.is_valid(raise_exception=True)
  File "/venv/lib/python3.11/site-packages/rest_framework/serializers.py", line 227, in is_valid
    self._validated_data = self.run_validation(self.initial_data)
                           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/venv/lib/python3.11/site-packages/rest_framework/serializers.py", line 429, in run_validation
    value = self.validate(value)
            ^^^^^^^^^^^^^^^^^^^^
  File "/venv/lib/python3.11/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 "/venv/lib/python3.11/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 "/venv/lib/python3.11/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

For the latest allauth, in the auth-code flow, the token variable already holds a dictionary with an id_token field so it's unnecessary to wrap the response. This pull request fixes the regression.

sp-luciano-chinke commented 1 year ago

My fault on that! Sorry and thanks! ❤️

ghost commented 1 year ago

Is there an ETA on when this fix is going to be released?

tadamcz commented 8 months ago

I'm confused: the commit with the fix is tagged as 5.0.2. I am on 5.0.2, and I still get the issue.

Specifically, my versions for dj-rest-auth and django-allauth are:

# pyproject.toml
dj-rest-auth = {extras = ["with-social"], version = "^5.0.2"}
# poetry.lock

[[package]]
name = "dj-rest-auth"
version = "5.0.2"
description = "Authentication and Registration in Django Rest Framework"
optional = false
python-versions = ">=3.6"
files = [
    {file = "dj-rest-auth-5.0.2.tar.gz", hash = "sha256:aad7d912476169e9991547bf98645344d3939be2d7052098048d819524c115d9"},
]

[package.dependencies]
Django = ">=3.2"
django-allauth = {version = ">=0.56.0,<0.58.0", optional = true, markers = "extra == \"with-social\""}
djangorestframework = ">=3.13.0"

[package.extras]
with-social = ["django-allauth (>=0.56.0,<0.58.0)"]

...

[[package]]
name = "django-allauth"
version = "0.57.0"
description = "Integrated set of Django applications addressing authentication, registration, account management as well as 3rd party (social) account authentication."
optional = false
python-versions = ">=3.7"
files = [
    {file = "django-allauth-0.57.0.tar.gz", hash = "sha256:a095ef0db7de305d9175772c78e765ebd5fceb004ae61c1383d7fc1af0f7c5b1"},
]

My traceback is (as far as I can tell) exactly identical to the OP:

Expand ``` Traceback (most recent call last): File "/usr/local/lib/python3.11/site-packages/allauth/socialaccount/providers/google/views.py", line 42, in complete_login identity_data = jwt.decode( ^^^^^^^^^^^ File "/usr/local/lib/python3.11/site-packages/jwt/api_jwt.py", line 210, in decode decoded = self.decode_complete( ^^^^^^^^^^^^^^^^^^^^^ File "/usr/local/lib/python3.11/site-packages/jwt/api_jwt.py", line 151, in decode_complete decoded = api_jws.decode_complete( ^^^^^^^^^^^^^^^^^^^^^^^^ File "/usr/local/lib/python3.11/site-packages/jwt/api_jws.py", line 198, in decode_complete payload, signing_input, header, signature = self._load(jwt) ^^^^^^^^^^^^^^^ File "/usr/local/lib/python3.11/site-packages/jwt/api_jws.py", line 254, in _load raise DecodeError(f"Invalid token type. Token must be a {bytes}") jwt.exceptions.DecodeError: Invalid token type. Token must be a The above exception was the direct cause of the following exception: Traceback (most recent call last): File "/usr/local/lib/python3.11/site-packages/asgiref/sync.py", line 534, in thread_handler raise exc_info[1] File "/usr/local/lib/python3.11/site-packages/django/core/handlers/exception.py", line 42, in inner response = await get_response(request) ^^^^^^^^^^^^^^^^^^^^^^^^^^^ File "/usr/local/lib/python3.11/site-packages/asgiref/sync.py", line 534, in thread_handler raise exc_info[1] File "/usr/local/lib/python3.11/site-packages/django/core/handlers/base.py", line 253, in _get_response_async response = await wrapped_callback( ^^^^^^^^^^^^^^^^^^^^^^^ File "/usr/local/lib/python3.11/site-packages/asgiref/sync.py", line 479, in __call__ ret: _R = await loop.run_in_executor( ^^^^^^^^^^^^^^^^^^^^^^^^^^^ File "/usr/local/lib/python3.11/site-packages/asgiref/current_thread_executor.py", line 40, in run result = self.fn(*self.args, **self.kwargs) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ File "/usr/local/lib/python3.11/site-packages/asgiref/sync.py", line 538, in thread_handler return func(*args, **kwargs) ^^^^^^^^^^^^^^^^^^^^^ File "/usr/local/lib/python3.11/contextlib.py", line 81, in inner return func(*args, **kwds) ^^^^^^^^^^^^^^^^^^^ File "/usr/local/lib/python3.11/site-packages/django/views/decorators/csrf.py", line 56, in wrapper_view return view_func(*args, **kwargs) ^^^^^^^^^^^^^^^^^^^^^^^^^^ File "/usr/local/lib/python3.11/site-packages/django/views/generic/base.py", line 104, in view return self.dispatch(request, *args, **kwargs) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ File "/usr/local/lib/python3.11/site-packages/django/utils/decorators.py", line 46, in _wrapper return bound_method(*args, **kwargs) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ File "/usr/local/lib/python3.11/site-packages/django/views/decorators/debug.py", line 92, in sensitive_post_parameters_wrapper return view(request, *args, **kwargs) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ File "/usr/local/lib/python3.11/site-packages/dj_rest_auth/views.py", line 48, in dispatch return super().dispatch(*args, **kwargs) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ File "/usr/local/lib/python3.11/site-packages/rest_framework/views.py", line 509, in dispatch response = self.handle_exception(exc) ^^^^^^^^^^^^^^^^^^^^^^^^^^ File "/usr/local/lib/python3.11/site-packages/rest_framework/views.py", line 469, in handle_exception self.raise_uncaught_exception(exc) File "/usr/local/lib/python3.11/site-packages/rest_framework/views.py", line 480, in raise_uncaught_exception raise exc File "/usr/local/lib/python3.11/site-packages/rest_framework/views.py", line 506, in dispatch response = handler(request, *args, **kwargs) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ File "/app/api/views.py", line 35, in post return super(GoogleLogin, self).post(request, *args, **kwargs) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ File "/usr/local/lib/python3.11/site-packages/dj_rest_auth/views.py", line 125, in post self.serializer.is_valid(raise_exception=True) File "/usr/local/lib/python3.11/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.11/site-packages/rest_framework/serializers.py", line 429, in run_validation value = self.validate(value) ^^^^^^^^^^^^^^^^^^^^ File "/usr/local/lib/python3.11/site-packages/dj_rest_auth/registration/serializers.py", line 158, in validate login = self.get_social_login(adapter, app, social_token, response={'id_token': id_token}) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ File "/usr/local/lib/python3.11/site-packages/dj_rest_auth/registration/serializers.py", line 62, in get_social_login social_login = adapter.complete_login(request, app, token, response=response) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ File "/usr/local/lib/python3.11/site-packages/allauth/socialaccount/providers/google/views.py", line 60, in complete_login raise OAuth2Error("Invalid id_token") from e allauth.socialaccount.providers.oauth2.client.OAuth2Error: Invalid id_token ```
tadamcz commented 8 months ago

Upon further investigation, it looks like the commit was first released under 4.0.0, but this doesn't explain why the problem should still occur. Should this be a new issue?

mcbarin commented 7 months ago

I'm having the exact same error; seems like it's still not fixed or we're doing something wrong.

Django==3.2.18
dj-rest-auth==5.0.2
django-allauth==0.60.1

Have you fixed this or found a workaround @tadamcz ?