import { useEffect, type ReactNode } from 'react' import { useAuth } from 'react-oidc-context' /** * Гейтит всё содержимое приложения по аутентификации. Если юзер не залогинен — * сразу редиректим на Keycloak (без промежуточной страницы "Вы не авторизованы" * и без красного 401 от axios). Пока auth state ещё определяется — показываем * нейтральный spinner. * * Сценарии: * - First visit, нет токена → signinRedirect → Keycloak login → redirect_uri → * onSigninCallback чистит URL → дети рендерятся. * - Истёк access_token, silent renew не успел → 401 от backend ловится в * {@link TokenSync} interceptor, который дёргает signinSilent/signinRedirect. * - Возврат с ошибкой OIDC (?error=access_denied) → не редиректим в цикле, * показываем сообщение. */ export function RequireAuth({ children }: { children: ReactNode }) { const auth = useAuth() const oidcError = typeof window !== 'undefined' && new URLSearchParams(window.location.search).get('error') useEffect(() => { if (oidcError) return if (auth.isLoading || auth.activeNavigator) return if (auth.isAuthenticated) return auth.signinRedirect().catch((err) => { // Не уйти на signinRedirect = Keycloak недоступен. Логируем, дальше // покажем сообщение об ошибке (auth.error будет выставлен). console.error('[auth] signinRedirect failed', err) }) }, [auth.isAuthenticated, auth.isLoading, auth.activeNavigator, oidcError]) if (oidcError) { return (
Keycloak вернул ошибку:{' '}
{oidcError}
{auth.error.message}