Что вы соберёте и зачем это нужно

Вы подключите реальный сервер Keycloak к приложению Next.js (App Router) через NextAuth.js, защитите страницы и получите плавный SSO-флоу. Никакой воды — только то, что реально работает в проде.

Быстрее релизы

Сократите настройку аутентификации ~на 30% за счёт проверенного стека и готовых сниппетов.

Готово к продакшену

SSO/MFA с первого дня: безопаснее дефолты и меньше «мин замедленного действия».

Довольные пользователи

Бесшовные сессии между приложениями и минимум «пожалуйста, войдите снова».

Чище эксплуатация

Централизованные пользователи/роли и меньше ручных ошибок в доступах.

Keycloak в двух словах

Keycloak — open-source сервер управления доступом и идентификацией. Он берёт на себя логин/логаут, управление пользователями, SSO и MFA, используя современные стандарты: OAuth 2.0, OpenID Connect и SAML. Ваше приложение остаётся лёгким, а всю тяжёлую работу делает Keycloak.

Быстрая модель

Realm — границы пользователей/клиентов. Client — ваше приложение. Provider — протокольный мост (OIDC/SAML). NextAuth.js общается с Keycloak по OIDC за вас.

Почему команды выбирают Keycloak

  • SSO по стандартам для множества приложений и сервисов.
  • Централизация пользователей, групп и ролей — проще управлять доступом.
  • MFA и тонкие политики без изобретения велосипеда.
  • Open source, активное комьюнити, enterprise-варианты.

Чек-лист перед интеграцией

  • Установлен Docker (для быстрого локального запуска Keycloak).
  • Next.js 14+ с App Router.
  • Выбор клиента: confidential (серверный, с секретом) или public (PKCE).

Быстрый запуск Keycloak

Поднимите Keycloak локально через Docker:

1docker run -p 8080:8080 -e KEYCLOAK_USER=admin -e KEYCLOAK_PASSWORD=admin jboss/keycloak

После запуска откройте http://localhost:8080/auth и войдите admin/admin. (В продакшене используйте современный образ с quay.io и надёжные креды.)

Создаём Realm без лишней магии

В админ-консоли создайте realm (например, MyRealm). Включите нужные self-service-фичи и настройте политики паролей/сессий. Начните с простого — детали докрутите позже.

Realms vs Clients

Realm хранит пользователей и конфиг приложений. Каждый Next.js-сервис (сайт, дашборд, API) обычно — отдельный client.

Клиент для Next.js: настройка

Создайте клиент (например, nextjs-client) с протоколом openid-connect. Задайте Root URL вашего приложения (например, http://localhost:3000) и добавьте корректные redirect URI и web origins для коллбеков NextAuth.js.

Минимальные настройки клиента

  1. Client Protocol: openid-connect
  2. Client ID: nextjs-client
  3. Access Type:
    • public (PKCE, без client secret), или
    • confidential (нужен clientSecret).
  4. Valid Redirect URIs: например http://localhost:3000/api/auth/callback/*
  5. Web Origins: например http://localhost:3000

Подключаем NextAuth.js в App Router

В NextAuth.js есть Keycloak provider. В App Router вы создаёте route.ts с экспортами хендлеров GET и POST.

Устанавливаем библиотеки

Поставьте NextAuth.js (и keycloak-js, если нужны фронт-канальные флоу):

1npm i next-auth keycloak-js

или

1yarn add next-auth keycloak-js

Переменные окружения

Создайте .env.local:

1KEYCLOAK_URL=http://localhost:8080/auth
2KEYCLOAK_REALM=MyRealm
3KEYCLOAK_CLIENT_ID=nextjs-client
4# Если используете confidential client:
5KEYCLOAK_CLIENT_SECRET=replace-with-generated-secret
6
7NEXTAUTH_URL=http://localhost:3000
8NEXTAUTH_SECRET=replace-with-strong-random-string

Сгенерируйте сильный секрет

Например, через OpenSSL: openssl rand -base64 32

Защищённые роуты и Session Provider

Создайте app/api/auth/[...nextauth]/route.ts:

1import NextAuth from 'next-auth'
2import KeycloakProvider from 'next-auth/providers/keycloak'
3
4const handler = NextAuth({
5  providers: [
6    KeycloakProvider({
7      clientId: process.env.KEYCLOAK_CLIENT_ID!,
8      clientSecret: process.env.KEYCLOAK_CLIENT_SECRET || '', // пропустите, если public client
9      issuer: `${process.env.KEYCLOAK_URL}/realms/${process.env.KEYCLOAK_REALM}`,
10    }),
11  ],
12  secret: process.env.NEXTAUTH_SECRET,
13  session: { strategy: 'jwt' },
14  callbacks: {
15    async jwt({ token, account, profile }) {
16      // Фиксируем важные поля Keycloak при первом входе
17      if (account) {
18        token.provider = 'keycloak'
19      }
20      return token
21    },
22    async session({ session, token }) {
23      // Делаем токен-поля доступными на клиенте
24      session.user = session.user || {}
25      ;(session.user as any).provider = token.provider
26      return session
27    },
28  },
29})
30
31export { handler as GET, handler as POST }

Это паттерн App Router — без NextApiRequest. Для аутентификации экспортируйте GET / POST.

Подключите провайдер сессии в app/layout.tsx:

1import './globals.css'
2import { SessionProvider } from 'next-auth/react'
3
4export default function RootLayout({ children }: { children: React.ReactNode }) {
5  return (
6    <html lang="ru">
7      <body>
8        <SessionProvider>{children}</SessionProvider>
9      </body>
10    </html>
11  )
12}

Создайте защищённую страницу app/protected/page.tsx:

1'use client'
2
3import { signIn, useSession } from 'next-auth/react'
4import { useEffect } from 'react'
5
6export default function ProtectedPage() {
7  const { data: session, status } = useSession()
8
9  useEffect(() => {
10    if (status === 'unauthenticated') {
11      signIn() // редирект в Keycloak через NextAuth
12    }
13  }, [status])
14
15  if (status === 'loading') return <div>Загрузка…</div>
16
17  return (
18    <main className="mx-auto max-w-2xl p-6">
19      <h1 className="mb-2 text-2xl font-semibold">Закрытый раздел</h1>
20      <p className="text-sm text-muted-foreground">
21        Добро пожаловать{session?.user?.name ? `, ${session.user.name}` : ''}! Вы успешно вошли.
22      </p>
23    </main>
24  )
25}

Харденинг и подсказки для продакшена

Рекомендуемые дефолты

  • Предпочитайте PKCE для public-клиентов.
  • Для confidential-клиентов храните KEYCLOAK_CLIENT_SECRET безопасно.
  • Используйте HTTPS end-to-end и защищённые cookies.
  • Регулярно ротируйте NEXTAUTH_SECRET.

Частые ошибки

  • Несовпадение redirect URI (следите за завершающими слешами).
  • Неверный realm/issuer — проверьте путь /auth/realms/<name>.
  • Смешивание примеров Pages Router в проекте App Router.
  • Непродуманная стратегия сессий (jwt vs database).

FAQ: частые ошибки и решения

Ошибка «Callback URL mismatch»?

Убедитесь, что в Keycloak добавлен ваш путь коллбэка NextAuth, например /api/auth/callback/*.

Нужен ли client secret?

Только для confidential клиентов (серверная сторона). Public-клиенты используют PKCE и секрета не требуют.

Как включить MFA?

Настройте MFA на уровне realm в Keycloak (настройки аутентификаторов/политик). NextAuth продолжит работать по стандартному OIDC-флоу.

Нужна помощь с интеграцией Keycloak ↔ Next.js?
Помогаю командам быстро и безопасно внедрять аутентификацию на связке Keycloak + NextAuth.js + App Router — без лишних экспериментов. Расскажите про стек и сроки — соберём прагматичный план.