Браузер не сохраняет файлы cookie HttpOnly React/Django

У меня есть интерфейс netlify app.mydomain.com и REST API django ninja api.mydomain.com. Когда я отправляю запрос на свою конечную точку входа, API успешно возвращается с ключом доступа (который я храню в состоянии приложения) и токеном обновления в виде безопасного файла cookie только для http. Я вижу, что этот файл cookie возвращается, просматривая заголовки ответов в инструментах разработки. Однако файл cookie вообще не сохраняется в браузере. Я ответил на множество других вопросов/ответов и считаю, что реализовал все необходимое, но он все еще не работает.

Мой вызов API входа из внешнего интерфейса:

await fetch(
  AUTH_URL_OBTAIN,
  {
    method: RequestMethod.POST,
    headers: {"Content-Type": "application/json"},
    body: JSON.stringify({username: formData.email, password: formData.password}),
    credentials: "include",
  },
);

На серверной стороне файл cookie устанавливается следующим образом:

response.set_cookie(
    key = "refresh",
    value=refresh_token,
    expires=datetime.fromtimestamp(refresh_token_payload["exp"], timezone.utc),
    httponly=True,
    samesite = "none",
    secure=True,
    path = "/api/auth/web/token-refresh",
    domain = ".mydomain.com",
)

У меня также установлены следующие настройки (замена значений переменных среды):

CSRF_TRUSTED_ORIGINS = ["https://app.mydomain.com"]
CORS_ALLOWED_ORIGINS = ["https://app.mydomain.com"]
CORS_ORIGIN_WHITELIST = ["https://app.mydomain.com"]
CORS_ALLOW_CREDENTIALS = True

Ответ на вход в систему предоставляет токен доступа (который работает, как и ожидалось — я могу прекрасно выполнять вызовы API, используя это, и иметь credentials: include на всех fetch запросах), а заголовки ответов приведены ниже:

Access-Control-Allow-Credentials: true

Access-Control-Allow-Origin: https://app.mydomain.com

Content-Length: 661

Content-Type: application/json; charset=utf-8

Cross-Origin-Opener-Policy: same-origin

Date: Thu, 06 Jun 2024 14:06:22 GMT

Referrer-Policy: same-origin

Server: daphne

Set-Cookie: refresh=ey...3uQ; Domain=.mydomain.com; expires=Sat, 06 Jul 2024 14:06:22 GMT; HttpOnly; Max-Age=2592000; Path=/api/auth/web/token-refresh; SameSite=none; Secure

Vary: origin

X-Content-Type-Options: nosniff

X-Frame-Options: DENY

Я сейчас в некоторой растерянности - буду очень признателен за любые советы, спасибо!

🤔 А знаете ли вы, что...
React позволяет создавать пользовательские интерфейсы для веб-приложений.


2
149
3

Ответы:

Политики безопасности браузера могут блокировать файлы cookie из/в запросы ajax. Видеть

Для API перекрестного происхождения я бы предпочел вообще не использовать файлы cookie. Представьте себе любой API-клиент, кроме браузера! Файлы cookie предназначены для отслеживания сеансов просмотра веб-сайта, а не для хранения состояния в произвольных http-клиентах.

Просто включите токен обновления в тело ответа и сохраните его также в состоянии вашего приложения.


Я реализовал множество решений такого типа, в которых файл cookie используется для включения учетных данных сообщения API и, следовательно, выдается на стороне API архитектуры.

Мне кажется, ваша проблема связана со свойством expires файла cookie. Это приводит к тому, что файл cookie становится постоянным, и я ожидаю, что он установлен неправильно. Все остальное выглядит правильно.

Я думаю, вы можете решить свою проблему, если удалите это свойство cookie. Выполнение do также является рекомендуемым методом обеспечения безопасности и приводит к созданию файла cookie сеанса, который удаляется при закрытии браузера.

Кроме того, невозможно делать предположения о форматах токенов обновления или полезных нагрузках. Вместо этого токен обновления считается просроченным, когда вы пытаетесь использовать его в emdpoint токена сервера авторизации и получаете ответ с кодом ошибки invalid_grant. Поэтому при использовании файлов cookie, представляющих токены, всегда учитывайте срок действия базового токена.


Решено

Это не имеет ничего общего ни с Django, ни с React. Это способ установки файла cookie.

  1. Файл cookie с path может быть установлен где угодно, но доступен только на этом пути и его дочернем элементе. Таким образом, вы можете увидеть файл cookie только при посещении страницы /api/auth/web/token-refresh
  2. Рассмотрите возможность использования Max-Age вместо Expires, так как это менее подвержено ошибкам. Это цитата со страницы MDN:

Expires доступен дольше, чем Max-Age, однако Max-Age менее подвержен ошибкам и имеет приоритет, если установлены оба параметра. Обоснование этого заключается в том, что когда вы устанавливаете дату и время Expires, они относятся к клиенту, на котором устанавливается файл cookie. Если на сервере установлено другое время, это может привести к ошибкам.

  1. Безопасный файл cookie можно настроить только через https или localhost.