Что вы соберёте и зачем это нужно
Вы подключите реальный сервер 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.
Минимальные настройки клиента
- Client Protocol: openid-connect
- Client ID: nextjs-client
- Access Type:
- public (PKCE, без client secret), или
- confidential (нужен
clientSecret
).
- Valid Redirect URIs: например
http://localhost:3000/api/auth/callback/*
- 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-флоу.