You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用dj-rest-auth实现Google登录时,兑换访问令牌失败

解决Google社交登录的invalid_grant(Malformed auth code)错误

问题详情

通过dj-rest-auth和Django REST Framework配置Google社交登录后,向接口传递授权码时收到400错误:

请求内容

{"code": "4%google-auth-code"}

返回内容

{"non_field_errors": ["Failed to exchange code for access token"]}

捕获的底层错误

Error retrieving access token: b'{\n  "error": "invalid_grant",\n  "error_description": "Malformed auth code."\n}'

已确认Google Cloud Console中的重定向URL配置正常。


当前代码配置

settings.py

INSTALLED_APPS = [
    ...
    'django.contrib.sites',
    'rest_framework',
    'rest_framework.authtoken',
    'dj_rest_auth',
    'dj_rest_auth.registration',
    'allauth',
    'allauth.account',
    'allauth.socialaccount',
    'allauth.socialaccount.providers.google',
    ...
]
MIDDLEWARE = [
    ...
    'allauth.account.middleware.AccountMiddleware',
]
SITE_ID = 1
SOCIAL_AUTH_GOOGLE_OAUTH2_KEY = 'my_social_key'
SOCIAL_AUTH_GOOGLE_OAUTH2_SECRET = 'google_secret'
SOCIALACCOUNT_PROVIDERS = {
    'google': {
        'APP': {
            'client_id': SOCIAL_AUTH_GOOGLE_OAUTH2_KEY,
            'secret': SOCIAL_AUTH_GOOGLE_OAUTH2_SECRET,
        },
    }
}
AUTHENTICATION_BACKENDS = [
    'allauth.account.auth_backends.AuthenticationBackend',
]
REST_FRAMEWORK = {
    'DEFAULT_AUTHENTICATION_CLASSES': [
        'rest_framework.authentication.TokenAuthentication',
    ]
}

user/urls.py

from django.urls import path
from user import views
app_name = 'user'
urlpatterns = [
    ...
    path('auth/google/', views.GoogleLogin.as_view(), name='google_login'),
    ...
]

user/views.py

from allauth.socialaccount.providers.google.views import GoogleOAuth2Adapter
from allauth.socialaccount.providers.oauth2.client import OAuth2Client
from dj_rest_auth.registration.views import SocialLoginView
class GoogleLogin(SocialLoginView):
    adapter_class = GoogleOAuth2Adapter
    callback_url = 'http://localhost:8000/api/auth/google/'
    client_class = OAuth2Client

requirements.txt

dj-rest-auth==6.0.0
django-allauth==0.61.0

解决方案

  • 解码URL编码的授权码:请求中的code包含%字符,说明是URL编码后的字符串,Google无法识别这种格式。需要前端在传递前用decodeURIComponent(code)解码;如果是测试场景,直接使用原始的授权码(不要带URL编码的转义字符)。如果前端无法处理,可在后端视图中添加解码逻辑:

    from urllib.parse import unquote
    from allauth.socialaccount.providers.google.views import GoogleOAuth2Adapter
    from allauth.socialaccount.providers.oauth2.client import OAuth2Client
    from dj_rest_auth.registration.views import SocialLoginView
    
    class GoogleLogin(SocialLoginView):
        adapter_class = GoogleOAuth2Adapter
        callback_url = 'http://localhost:8000/api/auth/google/'
        client_class = OAuth2Client
    
        def post(self, request, *args, **kwargs):
            if 'code' in request.data:
                request.data['code'] = unquote(request.data['code'])
            return super().post(request, *args, **kwargs)
    
  • 验证授权码有效性:确认授权码是Google OAuth2流程中正常返回的,未过期(有效期10分钟)、未被重复使用(授权码仅能使用一次),且没有被篡改。

  • 严格匹配回调URL:再次核对views.py中的callback_url与Google Cloud Console里配置的授权重定向URI,必须完全一致,包括协议(HTTP/HTTPS)、域名、端口、路径,不能有任何拼写或格式差异。

  • 核对客户端密钥与ID:确保SOCIAL_AUTH_GOOGLE_OAUTH2_KEY和SOCIAL_AUTH_GOOGLE_OAUTH2_SECRET与Google Cloud中的客户端ID、密钥完全匹配,没有多余空格或特殊字符。

  • 检查版本兼容性:确认dj-rest-auth 6.0.0与django-allauth 0.61.0的兼容性,可尝试更新到最新兼容版本,参考官方文档确认版本匹配关系。


内容的提问来源于stack exchange,提问作者Grister

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.17 12:10:13