Представьте два приложения. Первое — клиентский кабинет, где человек смотрит счета и меняет контактные данные. Второе — админка, где сотрудник правит тарифы и блокирует аккаунты. Пользователь один: Анна работает в компании и при этом сама является клиентом. Она открывает кабинет в одной вкладке, админку в другой, нажимает «Выйти» в первой — и видит, что вторая вкладка как ни в чём не бывало продолжает показывать форму тарифов.
Это не обязательно ошибка Keycloak. Чаще это следствие того, что у «вошёл», «разрешено» и «выход» в такой системе три разных механизма, и каждый живёт по своим правилам. Разберём, как они связаны, на примере этой пары приложений.
Одна личность, два набора полномочий
Начнём с того, чего хочется от схемы. Анна должна вводить пароль один раз. Кабинету нужно знать, что это именно она, чтобы показать её счета. Админке нужно знать то же самое и вдобавок то, что ей разрешено менять тарифы. Обратное тоже важно: обычный клиент Борис, зайдя на адрес админки, должен получить отказ, хотя аутентификация у него пройдёт успешно — он ведь существующий пользователь.
Здесь легко сделать главную ошибку: решить, что успешный вход и есть доступ. Аутентификация отвечает на вопрос «кто это», авторизация — на вопрос «что ему можно». Keycloak хорошо умеет первое и даёт материал для второго, но решение о разрешении действия в итоге принимает приложение, глядя на то, что ему пришло в токене. Если приложение проверило подпись и срок токена, а роли не посмотрело, Борис попадёт в админку с той же лёгкостью, что и Анна.
Realm, client и роль: кто за что отвечает
Три понятия Keycloak полезно различать не по определениям, а по тому, кто и что с ними делает.
Realm — это граница, внутри которой живут пользователи, их учётные данные, клиенты и сессии. Когда Анна вводит пароль, она вводит его в конкретном realm. Если оба приложения принадлежат одной организации и обслуживают одних и тех же людей, логично держать их в одном realm: тогда единый вход получается сам собой, потому что у пользователя одна запись и одна браузерная сессия в этом realm. Отдельный realm имеет смысл там, где нужны действительно разные наборы пользователей и разные политики — например, внешние клиенты и внутренние сотрудники, которые не должны пересекаться ни в чём. Но платой будет то, что единого входа между ними уже не будет: это две независимые области.
Client — это регистрация приложения в realm. Кабинет и админка получают каждый свой client, со своими адресами возврата после входа, своим секретом (если приложение способно его хранить) и своими настройками. Именно client отвечает на вопрос «для кого выпущен токен»: токен для кабинета и токен для админки — это два разных выпуска, даже если за ними стоит один человек.
Роль — метка полномочий, которую можно назначить пользователю или группе. Роли бывают уровня realm и уровня client. Практическое различие такое: роль realm — общий словарь организации, например «сотрудник»; роль client принадлежит конкретному приложению, например «менеджер тарифов» в client админки. Роль, которая имеет смысл только внутри одного приложения, лучше делать ролью этого client: так название не смешивается с чужими и не создаёт ложного впечатления, что оно значимо везде.
Как это выглядит в действиях людей
Администратор Keycloak заводит realm, два client и несколько ролей. Допустим, в client админки появляются роли «читатель тарифов» и «редактор тарифов», а в кабинете достаточно одной — «клиент». Затем он назначает Анне обе пары: она и клиент, и редактор. Борису назначает только «клиент».
Теперь посмотрим, что делает обычный пользователь. Анна открывает кабинет, её перенаправляют на страницу входа Keycloak, она вводит пароль, возвращается в кабинет уже с результатом входа. Затем открывает админку — и здесь пароль больше не спрашивают, потому что в браузере уже есть сессия Keycloak. Админка получает свой выпуск токена, в котором, при правильной настройке, указаны роли Анны именно для этого client. Борис проделает ровно тот же путь, но в его токене для админки нужных ролей не окажется. Вход у него завершится успешно, а вот действие — нет, если приложение проверяет роли.
| Вопрос | Где живёт ответ |
|---|---|
| Кто этот человек | Realm: пользователь и его учётные данные |
| Для какого приложения выпущен токен | Client: у кабинета и админки он свой |
| Какие полномочия назначены | Роли пользователя или группы |
| Можно ли выполнить это действие | Код приложения, читающий роли из токена |
Последняя строка таблицы — самая важная и самая часто забываемая.
Две жизни: браузерная сессия и токен
Теперь вернёмся к двум вкладкам. Чтобы понять, почему выход в одной из них не гасит другую, нужно развести два объекта, которые в разговорах обычно сливаются в слово «сессия».
Первый — сессия пользователя в Keycloak, привязанная к браузеру. Её признак — cookie, которую Keycloak ставит при входе, и серверная запись о ней. Именно благодаря ей Анна не вводит пароль второй раз при открытии админки. Второй объект — токены, выпущенные клиентам: access token, с которым приложение что-то делает, и связанные с ним токены обновления. У токенов собственные сроки жизни.
В документации Keycloak эти вещи разнесены по настройкам: в разделе Realm settings отдельно задаются время сессий, параметры cookies и время жизни токенов (Keycloak: Server administration, sessions and tokens). Само существование отдельных полей подсказывает главное: это независимые часы. Они могут показывать разное время, и это нормально.
Сравним их на условном примере. Допустим, срок жизни access token — несколько минут, а сессия в браузере — несколько часов. Тогда каждые несколько минут приложение будет получать свежий токен, пока сессия жива, и пользователь этого не заметит. Если же в какой-то момент сессия исчезнет, новый токен получить не удастся — но уже выпущенный токен останется годным до конца своего срока, если приложение проверяет его само, по подписи и дате. Числа здесь выдуманы для иллюстрации; на своём сервере смотрите значения в настройках вашего realm и не переносите чужие.
Почему короткий токен — не прихоть
Из этого следует практическое правило. Чем короче срок жизни access token, тем меньше окно, в течение которого приложение продолжает доверять токену после того, как у Keycloak пользователя уже «нет». Платой за короткий срок становится более частое обновление, то есть больше обращений к серверу Keycloak. Для двух небольших приложений эта цена обычно невелика, но решение зависит от нагрузки, и подбирать значение стоит измерением, а не угадыванием.
Нужен сервер под эту задачу?
Разверните VPS MAATRIX за пару минут: NVMe, AMD EPYC, root-доступ, локации Россия, США, Франция и Великобритания. Оплата картой РФ и по СБП.
Три события, которые путают: выход, истечение и отзыв
Теперь можно проследить, что на самом деле происходит в трёх ситуациях, которые снаружи похожи на одно и то же — «человек больше не имеет доступа».
Пользователь нажал «Выйти»
Анна нажимает «Выйти» в кабинете. Приложение направляет браузер на выход Keycloak, и тот завершает её сессию. После этого новое открытие любого приложения того же realm снова потребует пароль. Вот только вторая вкладка с админкой — это уже загруженная страница со своим собственным состоянием. Если она держит у себя токен и не обращается к Keycloak, то она ничего не узнает, пока не попытается получить новый токен или пока приложение само не проверит сессию.
Тут важная деталь, на которой строится вся тема: передача выхода самому приложению не происходит магически. В документации сказано, что распространение logout на клиент зависит от настроенного endpoint, а если нужные URL не заданы, Keycloak не передаёт выход клиенту (та же глава руководства администратора). Иными словами, чтобы админка узнала о выходе из кабинета, у её client должна быть настроена точка, на которую Keycloak сообщит об этом, а само приложение должно уметь на это сообщение отреагировать — например, завершить свою локальную сессию. Без этого приложение живёт на собственной сессии и своём токене.
Какие именно поля и в какой вкладке заполнять, зависит от версии Keycloak и типа приложения, поэтому сверяйтесь с документацией той версии, которую вы действительно развернули. Подготовить сервер можно по статье о установке и настройке Keycloak на VPS.
Время вышло само
Здесь никто ничего не нажимал. Токен просто достиг конца срока, а сессия Keycloak — конца своего. Это штатное завершение. Ключевое отличие от выхода в том, что никакого сообщения клиентам не отправляется: приложение узнаёт об истечении, только когда само сравнит дату токена с текущим временем или когда обновление токена вернёт отказ. Если приложение при этом хранит собственную длинную локальную сессию, оно может продолжить работу гораздо дольше, чем пользователь ожидает. Поэтому срок локальной сессии приложения должен быть согласован со сроками Keycloak, а не выбран «с запасом».
Администратор отозвал доступ
Теперь сценарий, ради которого многие и затевают всю историю. Сотрудник уволился, или у Анны сняли роль редактора. Администратор Keycloak удаляет пользователя, отключает его, завершает его сессии или меняет назначение ролей. С точки зрения Keycloak результат ясен: новые токены с прежними полномочиями он не выдаст. Но уже выпущенный access token — это подписанный документ, и приложение, которое проверяет подпись само, не обязано при каждом запросе спрашивать у Keycloak, не отозван ли он.
Поэтому честная формулировка такая: отзыв прекращает выдачу новых токенов, а судьба уже выпущенного зависит от того, как приложение его проверяет. Если проверка полностью автономная, токен будет принят до истечения срока. Если приложение при необходимости сверяется с Keycloak (например, для особо чувствительных операций), недействительность проявится раньше. Обещать, что любой JWT сразу перестаёт работать после выхода или отзыва, нельзя; это свойство конкретной связки Keycloak и вашего приложения, а не самого формата токена.
| Событие | Что происходит в Keycloak | Что может остаться у приложения |
|---|---|---|
| Пользователь вышел | Браузерная сессия завершена | Своя сессия и ещё не истёкший токен, если выход не передан клиенту |
| Срок истёк | Новые токены без повторного входа не выдаются | Всё, что приложение держит дольше срока токена |
| Доступ отозван администратором | Новые токены с прежними правами не выдаются | Выпущенный токен, пока он принимается без сверки |
Как сделать, чтобы вторая вкладка вела себя предсказуемо
Из разбора вытекают конкретные решения для нашей пары приложений. Они не универсальны, но хорошо ложатся на задачу.
- Короткий access token для админки. Админка опаснее кабинета, и окно доверия к уже выданному токену для неё стоит делать уже. Сроки задаются в настройках realm, а при необходимости различия между приложениями проверьте, какие параметры в вашей версии можно переопределять на уровне client.
- Настроенный выход для обоих client. Каждому приложению, которое должно реагировать на выход из другого, нужна точка, куда Keycloak сообщит о завершении сессии, и обработчик в самом приложении, который гасит локальную сессию.
- Локальная сессия не длиннее серверной. Если приложение выдаёт собственную cookie, её срок не должен намного переживать токен, иначе всё предыдущее теряет смысл.
- Проверка ролей на каждом чувствительном действии. Не на входе в приложение, а там, где что-то меняется: правка тарифа, блокировка аккаунта.
Отдельно о ролях в токене. Приложение должно читать роли именно своего client, а не любые роли подряд. Типичная ошибка — проверить, что в токене вообще есть слово «admin», не уточняя, чья это роль. Если названия в двух client совпадают, а проверка слишком мягкая, права кабинета могут случайно сойтись с правами админки. Давайте ролям говорящие и непохожие имена и привязывайте их к тому client, которому они принадлежат.
Проверяем, что приложение действительно смотрит на роли
Настроить Keycloak — половина дела. Вторая половина — убедиться, что приложения правильно им пользуются. Проверку удобно строить на двух живых пользователях: «Анна» с обеими ролями и «Борис» только с ролью клиента.
- Борис против админки. Войдите под Борисом и откройте адрес админки напрямую. Вход должен пройти, а доступ к функциям — быть отклонён. Если Борис видит форму тарифов, приложение проверяет только факт входа, и именно эту ошибку нужно исправлять в первую очередь.
- Борис и прямое действие. Не ограничивайтесь скрытой кнопкой. Попробуйте обратиться к API админки от имени Бориса. Скрытый элемент интерфейса — это не защита.
- Снятие роли у Анны. Уберите у неё «редактора тарифов» и понаблюдайте, через какое время и при каком событии админка перестанет её пускать. Заметьте разницу между моментом снятия роли и моментом, когда приложение это реально учло, — она примерно равна времени жизни ещё не истёкшего токена, если сверки нет.
- Выход в первой вкладке. Выйдите из кабинета и посмотрите, что произойдёт во второй вкладке сразу и после очередного действия. Результат зависит от того, настроен ли у client админки выход и обрабатывает ли его приложение.
- Просроченная сессия. Оставьте вкладку без действий дольше срока токена и сессии, затем нажмите что-нибудь. Ожидаемое поведение — переход на повторный вход, а не ошибка или молчаливое продолжение работы.
Результаты этих пяти опытов лучше записать в простую таблицу прямо у себя: «что ожидали / что получили». Расхождения почти всегда указывают на одно из трёх мест — настройку выхода у client, срок локальной сессии приложения или проверку ролей в коде.
Где всё это запускать
Keycloak — сервер с состоянием: он хранит пользователей, сессии и ключи подписи, поэтому ему нужны предсказуемые ресурсы и постоянный диск. На VPS MAATRIX вы получаете root-доступ, NVMe-накопитель и процессоры AMD EPYC, а локации в публичном предложении — UK, US, RU и FR. Для знакомства с Keycloak и пробной пары приложений можно начать с небольшой конфигурации, например Ba (1 vCPU, 2 ГБ RAM, 40 ГБ NVMe) или Uab (2 vCPU, 4 ГБ, 80 ГБ). Это лишь точки отсчёта, а не обещание ёмкости: сколько пользователей и входов выдержит ваш сервер, покажет только нагрузочная проверка с вашими настройками токенов и сессий. Если вы выбираете короткие токены и частое обновление, сервер будет получать больше обращений, и это стоит учесть при выборе плана. Заказ оформляется на странице аренды VPS, где доступна оплата картой РФ и через СБП, а сервер создаётся автоматически вскоре после оплаты.
Две вкладки, вторая попытка
Вернёмся к Анне и её двум вкладкам, теперь уже с понятными ожиданиями.
Анна нажимает «Выйти» в кабинете. Первая вкладка немедленно показывает страницу входа, потому что приложение само инициировало завершение сессии в Keycloak. Вторая вкладка с админкой — зависит от настройки. Если у client админки настроен выход и приложение умеет его принимать, то её локальная сессия закрывается, а следующее действие приводит к повторному входу. Если выход не настроен, админка не узнает ничего, пока не истечёт токен или не понадобится его обновление; после этого обновить его уже не получится, и Анну попросят войти заново. В окно между этими моментами уже выпущенный токен может приниматься, если приложение проверяет его автономно, — и именно для админки это окно нужно делать самым узким.
Если же в разгар этого администратор снял с Анны роль редактора, ожидаемое поведение такое: новая попытка получить токен вернёт уже урезанный набор ролей, а действие, требующее роли редактора, будет отклонено кодом приложения. И только проверка каждого шага на своём стенде отличает схему, которая так себя ведёт, от схемы, которая так выглядит.