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"
}

В чем мне нужна помощь:

  1. Как я могу извлечь и отправить серверные токены доступа/обновления для реагирования после успешного входа в систему?
  2. Должен ли я использовать конечную точку преобразования токена? Если да, то какой запрос я должен сделать и где?
  3. Или мне следует изменить поток перенаправления, чтобы включить токены во фрагмент 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

Краткое описание потока:

  1. Пользователь входит в систему через /auth/login/google-oauth2/.

  2. Конвейер создает JWT, устанавливает файлы cookie и перенаправляет на React.

  3. Интерфейс считывает access_token из файла cookie и использует его для запросов к API.

  4. После истечения срока действия срабатывает интерфейс:
    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/ для завершения процесса.

Вернуться на верх