React не получает токены API после перенаправления Google OAuth через social_django/drf-social-oauth2
Я внедряю Google OAuth2 для моего Django REST API с интерфейсом React. Базовый поток настроен правильно. У меня есть маршруты для:
urlpatterns = [
path("admin/", admin.site.urls),
path("api/v1/", include((v1_patterns, "v1"))),
path("api/v1/auth/", include("social_django.urls", namespace="social")),
path("api/v1/auth/token/", include("drf_social_oauth2.urls", namespace="oauth2")),
]
Также у меня есть:
INSTALLED_APPS = [
...
"drf_yasg",
"social_django",
"oauth2_provider",
"drf_social_oauth2",
...
]
SOCIAL_AUTH_URL_NAMESPACE = "social"
AUTHENTICATION_BACKENDS = (
"django.contrib.auth.backends.ModelBackend",
"social_core.backends.google.GoogleOAuth2",
"drf_social_oauth2.backends.DjangoOAuth2",
)
SOCIAL_AUTH_GOOGLE_OAUTH2_KEY = config("GOOGLE_OAUTH_CLIENT_ID")
SOCIAL_AUTH_GOOGLE_OAUTH2_SECRET = config("GOOGLE_OAUTH_CLIENT_SECRET")
SOCIAL_AUTH_GOOGLE_OAUTH2_SCOPE = ["email", "profile"]
SOCIAL_AUTH_GOOGLE_OAUTH2_EXTRA_DATA = [
"email",
"first_name",
"last_name",
"picture",
]
LOGIN_REDIRECT_URL = "http://127.0.0.1:5173"
# REST Framework general settings
REST_FRAMEWORK = {
"DEFAULT_AUTHENTICATION_CLASSES": (
"oauth2_provider.contrib.rest_framework.OAuth2Authentication",
"drf_social_oauth2.authentication.SocialAuthentication",
)
}
Для входа в систему я отправил запрос GET из браузера на http://localhost:8000/api/v1/auth/login/google-oauth2/
После отправки запроса в консоли я получаю:
api_container | [24/Jun/2025 13:04:19] "GET /api/v1/auth/login/google-oauth2/ HTTP/1.1" 302 0
api_container | [24/Jun/2025 13:04:20] "GET /api/v1/auth/complete/google-oauth2/?state=KYTUm5yi1NheUmc095zaRqIc3mZjsOLp&code=4%2F0AUJR-x4dcWMTghJHjPc1QbiPrCFo5lo2u9l1cYJ47F61fB0kIkQe4I0DFAt33UZOPBBI8g&scope=email+profile+https%3A%2F%2Fwww.googleapis.com%2Fauth%2Fuserinfo.email+https%3A%2F%2Fwww.googleapis.com%2Fauth%2Fuserinfo.profile+openid&authuser=0&prompt=none HTTP/1.1" 302 0
После успешного входа в систему я перенаправляюсь в свое приложение React (127.0.0.1:5173), но проблема в том, что никакие токены (доступа или обновления) клиенту не передаются. Я не знаю, как получить или отправить их, чтобы React мог аутентифицировать будущие вызовы API.
Я могу подтвердить, что после входа в систему база данных записывает адрес электронной почты, фотографию, имя, фамилию и токен доступа (от Google), но React ничего не получает.
Данные, которые у меня есть в базе данных в поле extra_data:
{
"hd": "domain",
"email": "my_email",
"expires": 3599,
"picture": "link",
"auth_time": 1750762274,
"last_name": "Doe",
"first_name": "John",
"token_type": "Bearer",
"access_token": "token"
}
В чем мне нужна помощь:
- Как я могу извлечь и отправить серверные токены доступа/обновления для реагирования после успешного входа в систему?
- Должен ли я использовать конечную точку преобразования токена? Если да, то какой запрос я должен сделать и где?
- Или мне следует изменить поток перенаправления, чтобы включить токены во фрагмент URL или что-то подобное?
Я хотел бы узнать, как интегрировать весь процесс — от входа в Google → публикации React до /convert-token/ → хранения токенов → использования токенов в аутентифицированных вызовах API.
Что я пробовал до сих пор:
- Настроен
social_djangoиdrf-social-oauth2 - Проверены циклы перенаправления и поля базы данных
- Просмотрел документы, но не нашел работающего примера интеграции React
Хорошо. После долгих поисков и попыток я нашел этот вариант.
Решение: JWT с Google OAuth через пользовательский конвейер и обновление на основе файлов cookie.
В settings.py настройте SOCIAL_AUTH_PIPELINE:
SOCIAL_AUTH_PIPELINE = (
"social_core.pipeline.social_auth.social_details",
"social_core.pipeline.social_auth.social_uid",
"social_core.pipeline.social_auth.auth_allowed",
"social_core.pipeline.social_auth.social_user",
"social_core.pipeline.social_auth.associate_by_email",
"social_core.pipeline.user.create_user",
"social_core.pipeline.social_auth.associate_user",
"social_core.pipeline.social_auth.load_extra_data",
"social_core.pipeline.user.user_details",
"users.pipeline.get_token_google_oauth", # <— Your custom step
)
Пользовательская функция конвейера: get_token_google_oauth
# users/pipeline.py
from django.shortcuts import redirect
from rest_framework_simplejwt.tokens import RefreshToken
def get_token_google_oauth(strategy, details, user=None, *args, **kwargs):
"""
After Google auth, generate JWT and send to client via cookies and redirect.
"""
if not user:
return redirect("http://127.0.0.1:5173/auth/error")
refresh = RefreshToken.for_user(user)
access = str(refresh.access_token)
refresh_t = str(refresh)
response = redirect("http://127.0.0.1:5173/")
response.set_cookie(
"refresh_token",
refresh_t,
httponly=True,
secure=False,
samesite="Lax",
path="/api/v1/auth/token/refresh/",
)
# Optionally expose the access token
response.set_cookie(
"access_token",
access,
httponly=False,
secure=False,
samesite="Lax",
)
return response
Этот шаг конвейера:
1. Создаем токены JWT (access + refresh).
2. Сохраняет refresh_token в виде HttpOnly cookie только для обновления URL-адреса.
3. Предоставляет access_token доступ к интерфейсу с помощью файлов cookie, не связанных только с HttpOnly.
4. Перенаправляет пользователя на ваше приложение React
Обновить конечную точку: TokenRefreshFromCookieView
# urls.py
from django.urls import path, include
from rest_framework_simplejwt.views import TokenRefreshView
from .views import TokenRefreshFromCookieView
urlpatterns = [
path("api/v1/auth/", include("social_django.urls", namespace="social")),
path(
"api/v1/auth/token/refresh/",
TokenRefreshFromCookieView.as_view(),
name="token_refresh",
),
]
Пользовательский просмотр для обновления токенов с помощью файлов cookie:
# views.py
from rest_framework.views import APIView
from rest_framework.response import Response
from rest_framework import status
from rest_framework.exceptions import AuthenticationFailed
from rest_framework_simplejwt.serializers import TokenRefreshSerializer
class TokenRefreshFromCookieView(APIView):
"""
Refresh access token using a refresh token from cookie or request body.
"""
def post(self, request, *args, **kwargs):
refresh = request.data.get("refresh") or request.COOKIES.get("refresh_token")
if not refresh:
raise AuthenticationFailed("No refresh token provided.")
serializer = TokenRefreshSerializer(data={"refresh": refresh})
serializer.is_valid(raise_exception=True)
access = serializer.validated_data["access"]
new_refresh = serializer.validated_data.get("refresh", refresh)
resp = Response({"access": access}, status=status.HTTP_200_OK)
resp.set_cookie(
"refresh_token",
new_refresh,
httponly=True,
secure=False,
samesite="Lax",
path="/api/v1/auth/token/refresh/",
)
return resp
Краткое описание потока:
Пользователь входит в систему через
/auth/login/google-oauth2/.Конвейер создает JWT, устанавливает файлы cookie и перенаправляет на React.
Интерфейс считывает
access_tokenиз файла cookie и использует его для запросов к API.После истечения срока действия срабатывает интерфейс:
POST /api/v1/auth/token/refresh/
браузер автоматически отправляет HttpOnly только5. View возвращает новый
accessтокен (и, возможно, новыйrefresh) в файлах cookie и в теле файла.
Если у вас возникнут какие-либо проблемы или у вас будут какие-либо предложения, я буду рад их выслушать.
Причина, по которой ваше приложение React не получает никаких токенов после входа в Google, заключается в том, что Django управляет потоком OAuth и аутентифицирует пользователя, но не передает токены доступа или обновления автоматически с вашего сервера на внешний интерфейс. Как только Google перенаправляет обратно на Django, он просто регистрирует пользователя и перенаправляет на ваш LOGIN_REDIRECT_URL (который является вашим приложением React), но не включает никаких токенов. Чтобы устранить эту проблему, вы должны выполнить дополнительный шаг: разработать пользовательское представление Django, которое перехватывает перенаправление, извлекает токен доступа Google из данных социальной аутентификации пользователя, вошедшего в систему, и впоследствии перенаправляет на ваше приложение React, используя этот токен, включенный в URL (например, ?google_token=...). В вашем приложении React извлеките этот токен из URL-адреса и немедленно отправьте POST-запрос в /api/v1/auth/token/convert-token/, включая ваш client_id, client_secret, backend=google-oauth2 и полученный токен. Эта конечная точка предоставит вам токены доступа к вашему собственному API и обновления, которые вы затем сможете хранить и использовать для всех последующих аутентифицированных запросов API. По сути, Django выполнил свою задачу; теперь React просто нужно вызвать /convert-token/ для завершения процесса.