Ошибка Oauth Supabase Keycloak: Неверное состояние потока, действительное состояние потока не найдено

Вопрос или проблема

Во-первых, я тщательно искал ответ в Google и проверял обсуждения на форумах. Попробовал все, что нашел, но ничего не сработало. Вот я здесь.
Сначала о настройках.
Я запускаю все локально. Я использую Docker для Keycloak и саморазмещенную версию Supabase.
Настройки клиента Keycloak:

Допустимые URI перенаправления: http://localhost:3000/auth/callback; http://localhost:8000/auth/v1/callback
Web Origins: http://localhost:3000; http://localhost:8000
Аутентификация клиента: true

Docker-compose.yml для Supabase

 GOTRUE_EXTERNAL_KEYCLOAK_ENABLED: "true"
      GOTRUE_EXTERNAL_KEYCLOAK_CLIENT_ID: "supabase"
      GOTRUE_EXTERNAL_KEYCLOAK_SECRET: "0L3PRTgpQNx4hnkdamvjQYg8PiZqbS5x"
      GOTRUE_EXTERNAL_KEYCLOAK_URL: "http://localhost:8080/realms/master"
      GOTRUE_EXTERNAL_KEYCLOAK_REDIRECT_URI: "http://localhost:3000/auth/callback"

Переменные среды docker-compose для Supabase

ADDITIONAL_REDIRECT_URLS="http://localhost:3000/auth/callback"

Я использую шаблон Supabase для Nextjs.
Я добавил следующее в файл действий.

export const signInwithKeycloak = async () => {
  const supabase = createClient();

  const { data, error } = await supabase.auth.signInWithOAuth({
    provider: "keycloak",
    options: {
      scopes: "openid",
      redirectTo: "http://localhost:3000/auth/callback",
    },
  });

  if (error) {
    console.error("Ошибка OAuth:", error.message);
    return encodedRedirect("error", "/sign-in", error.message);
  }

  console.log("Данные ответа OAuth из действий:", data); // Логируем данные ответа, чтобы убедиться, что вы получаете правильный URL

  return redirect(data.url); // Убедитесь, что это перенаправляет корректно
};

В auth/callback/route.ts

import { createClient } from "@/utils/supabase/server";
import { NextResponse } from "next/server";

export async function GET(request: Request) {
  const requestUrl = new URL(request.url);
  const code = requestUrl.searchParams.get("code");
  const origin = requestUrl.origin;
  const redirectTo = requestUrl.searchParams.get("redirect_to")?.toString();

  const supabase = createClient();

  if (code) {
    console.log("Код авторизации найден в URL:", code);
    // Пытаемся обменять код авторизации на сессию
    const { data, error } = await supabase.auth.exchangeCodeForSession(code);
    console.log("данные из callback", data);
    if (error) {
      console.error("Ошибка обмена кода на сессию:", error.message);
      return NextResponse.redirect(
        `${origin}/sign-in?error=${encodeURIComponent(error.message)}`
      );
    }
  } else {
    console.error("Код авторизации не найден в URL.");
    return NextResponse.redirect(
      `${origin}/sign-in?error=Код авторизации отсутствует`
    );
  }

  if (redirectTo) {
    return NextResponse.redirect(`${origin}${redirectTo}`);
  }

  return NextResponse.redirect(`${origin}/protected`);
}

На странице входа я просто добавил кнопку и установил соответствующий formAction.

Когда я нажимаю “Войти”, затем кнопку “войти с помощью Keycloak”, я перенаправляюсь на страницу входа Keycloak. Когда я успешно вхожу, меня перенаправляют на страницу входа приложения с ошибкой “некорректное состояние потока, состояние потока не найдено”.

Когда я проверяю куки, я вижу “sb-localhost-auth-token-code-verifier”.
Когда я проверяю сетевую активность:

URL запроса: 
http://localhost:8000/auth/v1/authorize?provider=keycloak&redirect_to=http%3A%2F%2Flocalhost%3A3000%2Fauth%2Fcallback&scopes=openid&code_challenge=Ayzoh0qqlZK9q_BPQRZ4-ao28xkH4C7tvtpuOI3ptFU&code_challenge_method=s256

Данные
provider: keycloak
redirect_to: http://localhost:3000/auth/callback
scopes: openid
code_challenge: Ayzoh0qqlZK9q_BPQRZ4-ao28xkH4C7tvtpuOI3ptFU
code_challenge_method: s256
http://localhost:8080/realms/master/protocol/openid-connect/auth?client_id=supabase&redirect_to=http%3A%2F%2Flocalhost%3A3000%2Fauth%2Fcallback&redirect_uri=http%3A%2F%2Flocalhost%3A3000%2Fauth%2Fcallback&response_type=code&scope=profile+email+openid&state=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJleHAiOjE3MjgxMDQxODcsInNpdGVfdXJsIjoiaHR0cDovL2xvY2FsaG9zdDozMDAwIiwiaWQiOiIwMDAwMDAwMC0wMDAwLTAwMDAtMDAwMC0wMDAwMDAwMDAwMDAiLCJmdW5jdGlvbl9ob29rcyI6bnVsbCwicHJvdmlkZXIiOiJrZXljbG9hayIsInJlZmVycmVyIjoiaHR0cDovL2xvY2FsaG9zdDozMDAwL2F1dGgvY2FsbGJhY2siLCJmbG93X3N0YXRlX2lkIjoiMzgyZDFhYTEtMzNmMi00NWM3LWI5NGItMzk3YTg5YTBlMjgxIn0.wy5N_hLNJqvh_YNBDrFeuea92KeOdL_ir0eHWwqYz9I

Данные
client_id: supabase
redirect_to: http://localhost:3000/auth/callback
redirect_uri: http://localhost:3000/auth/callback
response_type: code
scope: profile email openid
state: eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJleHAiOjE3MjgxMDQxODcsInNpdGVfdXJsIjoiaHR0cDovL2xvY2FsaG9zdDozMDAwIiwiaWQiOiIwMDAwMDAwMC0wMDAwLTAwMDAtMDAwMC0wMDAwMDAwMDAwMDAiLCJmdW5jdGlvbl9ob29rcyI6bnVsbCwicHJvdmlkZXIiOiJrZXljbG9hayIsInJlZmVycmVyIjoiaHR0cDovL2xvY2FsaG9zdDozMDAwL2F1dGgvY2FsbGJhY2siLCJmbG93X3N0YXRlX2lkIjoiMzgyZDFhYTEtMzNmMi00NWM3LWI5NGItMzk3YTg5YTBlMjgxIn0.wy5N_hLNJqvh_YNBDrFeuea92KeOdL_ir0eHWwqYz9I
http://localhost:3000/auth/callback?state=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJleHAiOjE3MjgxMDQxODcsInNpdGVfdXJsIjoiaHR0cDovL2xvY2FsaG9zdDozMDAwIiwiaWQiOiIwMDAwMDAwMC0wMDAwLTAwMDAtMDAwMC0wMDAwMDAwMDAwMDAiLCJmdW5jdGlvbl9ob29rcyI6bnVsbCwicHJvdmlkZXIiOiJrZXljbG9hayIsInJlZmVycmVyIjoiaHR0cDovL2xvY2FsaG9zdDozMDAwL2F1dGgvY2FsbGJhY2siLCJmbG93X3N0YXRlX2lkIjoiMzgyZDFhYTEtMzNmMi00NWM3LWI5NGItMzk3YTg5YTBlMjgxIn0.wy5N_hLNJqvh_YNBDrFeuea92KeOdL_ir0eHWwqYz9I&session_state=181a8fe2-2bf5-4279-8bfd-c8880d89c51c&iss=http%3A%2F%2Flocalhost%3A8080%2Frealms%2Fmaster&code=03399bd7-f454-4e89-bd7d-e04eec6908d4.181a8fe2-2bf5-4279-8bfd-c8880d89c51c.b37b3d25-c578-4ad6-afa8-03f6a6bbae02

Данные
state: eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJleHAiOjE3MjgxMDQxODcsInNpdGVfdXJsIjoiaHR0cDovL2xvY2FsaG9zdDozMDAwIiwiaWQiOiIwMDAwMDAwMC0wMDAwLTAwMDAtMDAwMC0wMDAwMDAwMDAwMDAiLCJmdW5jdGlvbl9ob29rcyI6bnVsbCwicHJvdmlkZXIiOiJrZXljbG9hayIsInJlZmVycmVyIjoiaHR0cDovL2xvY2FsaG9zdDozMDAwL2F1dGgvY2FsbGJhY2siLCJmbG93X3N0YXRlX2lkIjoiMzgyZDFhYTEtMzNmMi00NWM3LWI5NGItMzk3YTg5YTBlMjgxIn0.wy5N_hLNJqvh_YNBDrFeuea92KeOdL_ir0eHWwqYz9I
session_state: 181a8fe2-2bf5-4279-8bfd-c8880d89c51c
iss: http://localhost:8080/realms/master
code: 03399bd7-f454-4e89-bd7d-e04eec6908d4.181a8fe2-2bf5-4279-8bfd-c8880d89c51c.b37b3d25-c578-4ad6-afa8-03f6a6bbae02

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

Ответ или решение

Проблема, с которой вы столкнулись, связана с ошибкой "Invalid flow state, no valid flow state found" при использовании Keycloak в качестве провайдера OAuth с Supabase. Давайте разберем возможные причины возникновения этой ошибки и шаги по её устранению.

1. Проверьте настройки Keycloak

Убедитесь, что вы правильно настроили клиент в Keycloak. Следующие пункты могут быть важны:

  • Valid Redirect URIs: Убедитесь, что вы используете правильные URI. Поскольку у вас есть несколько окружений (localhost:3000 и localhost:8000), убедитесь, что оба указаны корректно и совпадают с тем, что используется в приложении.
  • Web Origins: Убедитесь, что в этом поле указаны все нужные origins, например http://localhost:3000 и http://localhost:8000.

2. Проверьте конфигурацию Supabase

Ваши параметры в файле docker-compose.yml выглядят корректными, но обратите внимание на следующее:

  • GOTRUE_EXTERNAL_KEYCLOAK_REDIRECT_URI: Убедитесь, что этот URI точно совпадает с одним из указанных в Keycloak. Если в Keycloak указано http://localhost:3000/auth/callback, то эта строка должна совпадать.

3. Коды и состояние (state)

При обмене кода на сессию в вашей функции GET в auth/callback/route.ts необходимо убедиться, что состояние (state), отправленное на сервер Keycloak, совпадает с тем состоянием, которое вы получили при возврате:

  • Проверьте, что code_verifier и code_challenge правильно генерируются и хранятся в cookie, чтобы они могли быть использованы при обмене кода.

4. Проверьте обработку состояния

Когда вы переводите запрос на сервер Keycloak, проверьте, правильно ли вы обрабатываете поле state:

const { data, error } = await supabase.auth.exchangeCodeForSession(code);

Проверьте логи или отладочную информацию, чтобы понять, корректно ли передается состояние и совпадает ли оно с правильным значением.

5. Ответы на запросы

При проверке сетевой активности, обратите внимание на следующее:

  • Запросы к authorize и token должны корректно указывать state, и это состояние должно храниться между запросами.

6. Другие соображения

  • Попробуйте использовать другой браузер или режим инкогнито, чтобы избежать кэширования или старых cookies.
  • Проверьте версии используемых библиотек (@supabase/supabase-js, Keycloak и т.д.), так как иногда ошибки могут быть связаны с несовместимостью версий.

7. Логи и отладка

Соберите и проанализируйте логи как Keycloak, так и Supabase, чтобы выявить дополнительные подсказки. Если возникнут повторные ошибки, возможно, стоит включить дополнительную отладочную информацию.

Если все вышеперечисленное не помогает решить проблему, вы можете рассмотреть возможность полной переустановки окружения или обращения к сообществу Supabase и Keycloak за поддержкой, предоставив все детали конфигурации.

В случае возникновения дополнительных вопросов или необходимости в помощи, пожалуйста, дайте знать!

Оцените материал
Добавить комментарий

Капча загружается...