SSO и вход через провайдеров
Помимо пароля, Gotcha умеет входить через внешних провайдеров: универсальный OIDC (любой совместимый IdP — Keycloak, Authentik, Auth0 и т.п.), Яндекс ID и VK ID. Каждый провайдер включается независимо переменными окружения сервера — настройка на уровне инсталляции, доступа из UI для неё нет.
Секреты провайдеров, заданных переменными окружения инстанса, живут только в памяти процесса — в базе их нет.
Отдельно от них существует per-org SSO: инстанс-админ настраивает OIDC для конкретной организации через интерфейс, и там client_secret хранится в базе (таблица org_sso), зашифрованным мастер-ключом GOTCHA_SECRET_KEY. Это разные механизмы, и утверждение «секретов в базе нет» относится только к первому.
Общий принцип
Провайдер включается булевым флагом *_ENABLED; если он включён, но обязательные для него переменные (client id/secret и т.п.) не заданы — сервер откажется стартовать с понятной ошибкой конфигурации. Включённые провайдеры появляются кнопками входа на странице логина.
Callback (redirect URI), который нужно зарегистрировать в настройках приложения у провайдера, всегда имеет вид:
{GOTCHA_BASE_URL}/auth/oauth/{provider}/callback
где {provider} — oidc, yandex или vk в зависимости от провайдера, а {GOTCHA_BASE_URL} — тот же адрес, что задан в GOTCHA_BASE_URL сервера (например, https://gotcha.example.com). Например, для generic OIDC это будет https://gotcha.example.com/auth/oauth/oidc/callback. URI не конфигурируется отдельно — он всегда строится по этой схеме, поэтому важно зарегистрировать у провайдера точно такой же адрес.
Яндекс ID и VK ID сами подтверждают адрес пользователя, поэтому по ним разрешены и автосоздание аккаунта, и автопривязка входа к существующему по email. У generic OIDC заявленный email/email_verified может подделать сам IdP — по умолчанию (GOTCHA_OIDC_TRUST_EMAIL=false) вход через него работает только для уже привязанных аккаунтов; самостоятельная регистрация и автопривязка по email включаются явно, см. ниже.
Generic OIDC — пошагово
- В консоли своего IdP (Keycloak, Authentik, Auth0, Zitadel и т.п.) заведите новое OAuth/OIDC-приложение (client) типа “confidential”/“web”.
- В качестве redirect URI укажите
{GOTCHA_BASE_URL}/auth/oauth/oidc/callback— точно так, с вашим реальнымGOTCHA_BASE_URL. - Скопируйте Issuer (обычно вида
https://idp.example.com/realms/myrealm— базовый адрес, по которому доступен.well-known/openid-configuration), Client ID и Client secret из настроек приложения в IdP. - Задайте переменные окружения сервера:
GOTCHA_OIDC_ENABLED=true
GOTCHA_OIDC_ISSUER=https://idp.example.com/realms/myrealm
GOTCHA_OIDC_CLIENT_ID=<client id из IdP>
GOTCHA_OIDC_CLIENT_SECRET=<client secret из IdP>
GOTCHA_OIDC_SCOPES=openid email profile # необязательно, это и есть значение по умолчанию
GOTCHA_OIDC_DISPLAY_NAME=Corp SSO # необязательно, подпись кнопки на /login (по умолчанию "OIDC")
- Перезапустите сервер. На странице
/loginпоявится кнопка «Войти через {GOTCHA_OIDC_DISPLAY_NAME или OIDC}».
Gotcha сам сходит по {issuer}/.well-known/openid-configuration за адресами авторизации/токена и JWKS — вручную их указывать не нужно.
По умолчанию этого достаточно только для входа тех, чей аккаунт уже привязан к этому провайдеру. Чтобы через этот же OIDC можно было САМОСТОЯТЕЛЬНО зарегистрироваться (открытая регистрация или приглашение) или автоматически привязать вход к существующему аккаунту по совпадению email, добавьте:
GOTCHA_OIDC_TRUST_EMAIL=true
Включайте это только если IdP — ваш собственный, одно-тенантный (свой Keycloak/Authentik/Zitadel и т.п.), и вы сами управляете тем, кто в нём заводит учётные записи. Не включайте для публичного мульти-тенантного IdP (общий Google-тенант, общедоступный Auth0 и т.п.) — там произвольный человек может завести директорию и указать в ней чужой email, а GOTCHA_OIDC_TRUST_EMAIL=true заставит Gotcha поверить этому на слово и отдать доступ к аккаунту с таким адресом.
Яндекс ID
- Зарегистрируйте приложение в Яндекс OAuth (или ID.Yandex — консоль разработчика Яндекса).
- Redirect URI:
{GOTCHA_BASE_URL}/auth/oauth/yandex/callback. - Скопируйте ID и Пароль (secret) приложения.
- Переменные окружения:
GOTCHA_YANDEX_ENABLED=true
GOTCHA_YANDEX_CLIENT_ID=<ID приложения>
GOTCHA_YANDEX_CLIENT_SECRET=<пароль приложения>
Кнопка на /login подписана «Войти через Яндекс».
VK ID
- Зарегистрируйте приложение в кабинете VK ID для разработчиков.
- Redirect URI:
{GOTCHA_BASE_URL}/auth/oauth/vk/callback. - Скопируйте ID приложения и защищённый ключ (client secret).
- Переменные окружения:
GOTCHA_VK_ENABLED=true
GOTCHA_VK_CLIENT_ID=<ID приложения>
GOTCHA_VK_CLIENT_SECRET=<защищённый ключ>
Кнопка на /login подписана «Войти через VK».
Как это работает при входе
- Если email из провайдера уже привязан к существующему аккаунту (или совпадает с verified email существующего пользователя) — вход сразу выпускает сессию.
- Если аккаунта с таким email ещё нет — дальнейшее зависит от
GOTCHA_REGISTRATION_MODE: приopenаккаунт появляется при первом входе через провайдера (действующее приглашение на этот email, если оно есть, принимается по пути); приinviteновый пользователь провизионируется только по действующему приглашению (см. Приглашение участников) — без него вход отклоняется; приclosedновых аккаунтов не появляется вообще. - Из профиля (
/profile) залогиненный пользователь может дополнительно привязать провайдера к своему существующему аккаунту тем же потоком (?link=1).
Отличие от enterprise-SSO по домену
Отдельно от этих инстанс-уровневых провайдеров у каждой организации есть собственная опциональная секция SSO в /orgs/{id}/settings: свой OIDC-провайдер для входа только участников с определённым доменом email, с опцией «enforced» (принудительный SSO для этого домена — пароль и общие провайдеры перестают работать для таких email). Сама страница настроек доступна owner’у или admin’у организации, но секция SSO внутри неё показывается только owner’у организации, а отдельно от этого — любому, кто помечен как администратор инстанса: это отдельный флаг, не связанный ни с одной ролью в организации, поэтому админ инстанса видит секцию, даже не будучи владельцем этой организации, а admin организации, не являющийся при этом админом инстанса, не видит секцию вовсе. Одной видимости всё равно недостаточно для настройки: включить или удалить федерацию может только аккаунт со статусом администратора инстанса — владелец организации, не являющийся админом инстанса, видит текущий статус SSO, но не форму настройки, и ownership организации никак не влияет на право настраивать/удалять. Разделение существует потому, что само-обслуживаемая настройка SSO владельцем организации на непроверенный домен — вектор захвата чужого аккаунта; подключить домен может только тот, кому оператор инстанса доверяет именно этот домен.
Форма настройки принимает issuer (обязательно https://), client id, client secret, домен (email участников, которых это затрагивает) и роль по умолчанию (member или admin) — роль, которую получит человек, впервые входящий по этому SSO и ещё не состоящий в организации. Redirect URI для регистрации у своего IdP: {GOTCHA_BASE_URL}/auth/oauth/sso-{ID организации}/callback (ID организации виден в адресной строке страницы настроек). IdP обязан подтверждать email (email_verified) — в отличие от инстанс-уровневого generic OIDC, здесь этого нельзя ни включить, ни выключить отдельной переменной: непроверенный email отклоняется всегда, а проверенный email вне указанного домена — тоже (IdP мог его подделать).
Страница /sso — отдельный от /login вход специально для этого механизма: ссылка «Вход через SSO» есть внизу и /login, и /register. Пользователь вводит рабочий email, сервер ищет организацию по домену этого email и, если она нашлась, перенаправляет на её OIDC-провайдера; если для домена SSO не настроен — форма отвечает «SSO для этого домена не настроен» на этой же странице. Как и на /login//register, это отдельный от них поток — попытка войти паролем на /login с email из домена, где enforced=true, отклоняется с сообщением «Ваша организация требует вход через SSO — используйте „Вход через SSO“», и то же сообщение получит попытка зарегистрироваться на /register с таким email.
Что конкретно ломает enforced=true. С момента включения все, у кого email оканчивается на этот домен, теряют вход паролем и общими провайдерами (Яндекс/VK/generic OIDC) целиком — независимо от того, состоят ли они уже в этой организации, и независимо от роли внутри неё: enforced привязан к домену email, а не к членству. Единственный путь входа — /sso с этим доменом. Уже существующий аккаунт с подтверждённым email из этого домена при первом входе через /sso автоматически добавляется в организацию с ролью по умолчанию, если ещё не состоял в ней; если состоял — роль не меняется. Отключить enforced или снять весь SSO-конфиг организации может только администратор инстанса — у самого владельца организации права на это нет (см. выше), поэтому при потере доступа к своему IdP владелец организации не может откатить это переключение сам, только попросить администратора инстанса.
Что дальше
- Команды и роли — приглашения, без которых новый пользователь через OAuth не заведётся.
- Конфигурация — остальные серверные переменные окружения.