Разработчикам Кабинет
Единый вход

Вход через 15Reg ID

Добавьте на свой сайт кнопку «Войти через 15reg». Пользователь входит в знакомый аккаунт, а ваш сайт получает подтверждение личности.

  1. Пользователь нажимает «Войти через 15reg».
  2. На id.15reg.ru входит и разрешает передать выбранные данные.
  3. Сайт получает одноразовый код, проверяет ответ и открывает свою сессию.

Что получит сайт

Всегда — постоянный идентификатор аккаунта. С разрешением profile — имя и имя пользователя; с email — почту и отметку о её подтверждении.

Что остаётся в 15reg

Пароль, сообщения, контакты и другие данные соцсети не передаются. Права и заказы внешнего проекта остаются в его собственной базе.

Самый короткий путь

Зарегистрируйте проект, добавьте точный адрес возврата и настройте свою библиотеку OpenID Connect: адрес провайдера https://id.15reg.ru, ID клиента и PKCE S256. Начните с openid.

Кабинет 15Reg ID

Зарегистрируйте проект или управляйте выданными доступами.

Открыть кабинет

Интеграция для разработчика

1. Отдельный клиент для каждого приложения
  1. Войдите в кабинет 15Reg ID и создайте тестовый клиент. Для сайта выберите web, для Android — android. Клиент принадлежит текущему аккаунту.
  2. Укажите точный redirect URI, включая схему, порт и путь. Рабочее приложение требует HTTPS. HTTP разрешён только для loopback в тестовом web-клиенте. Маски, URL с паролем и фрагменты запрещены.
  3. Сохраните client_id и issuer https://id.15reg.ru. Public-клиент с PKCE не получает client_secret. Зарегистрируйте отдельные клиенты для теста, production и Android.
  4. При необходимости заранее зарегистрируйте точные post-logout redirect URI. Серверный back-channel callback требует HTTPS и включения его origin оператором ID.

Кабинет использует POST /v1/id/clients на основном домене с вашей обычной сессией и CSRF. Это пример тела, а не публичная регистрация без авторизации:

{
  "name": "Мой проект — тест",
  "environment": "test",
  "platform": "web",
  "redirectUris": [
    "http://127.0.0.1:8080/callback"
  ],
  "postLogoutRedirectUris": []
}

Для серверного клиента API также принимает publicJwks и использует private_key_jwt. Передавайте только публичную часть ключа. Закрытый ключ остаётся на сервере вашего проекта. Среда test меняет регистрацию клиента и допустимые callback, но использует общие аккаунты ID: создайте отдельные тестовые аккаунты.

2. Authorization Code + PKCE S256

Получайте endpoints и JWKS через OpenID Connect discovery. Используйте поддерживаемую OIDC-библиотеку. Встроенная регистрация клиентов, implicit flow и password grant недоступны.

  1. Для каждого входа создайте новые state, nonce и PKCE verifier. Сохраните одноразовый запрос со сроком и привязкой к браузеру.
  2. Откройте authorization URL. ID предлагает вход, продолжение с известным аккаунтом, смену аккаунта и согласие на конкретные scopes.
  3. На callback проверьте state, браузерную привязку и срок. Атомарно заберите одноразовый запрос, затем обменяйте code с исходным verifier.
  4. Проверьте подпись JWT через JWKS, точные issuer и audience, nonce и время. Создайте собственную сессию проекта, используя идентичность iss + sub.

Фрагменты ниже показывают операции SDK. Полный пример с PostgreSQL, сессией браузера и одноразовым flow находится в apps/id-example релизного исходного кода.

import * as oidc from 'openid-client'; // 6.8.9, Node 24

const config = await oidc.discovery(
  new URL('https://id.15reg.ru'), process.env.ID_CLIENT_ID,
  { token_endpoint_auth_method: 'none' }, oidc.None()
);
oidc.enableNonRepudiationChecks(config);

const state = oidc.randomState();
const nonce = oidc.randomNonce();
const verifier = oidc.randomPKCECodeVerifier();
const url = oidc.buildAuthorizationUrl(config, {
  response_type: 'code', scope: 'openid profile',
  redirect_uri: 'https://project.example/callback',
  state, nonce,
  code_challenge: await oidc.calculatePKCECodeChallenge(verifier),
  code_challenge_method: 'S256'
});
// Сначала сохраните state, nonce, verifier и срок 10 минут
// в серверной БД с привязкой к браузерной сессии.
// Затем отправьте браузер на url.href.
// flow загружен по state и привязан к той же браузерной сессии.
// Атомарно пометьте его использованным ДО обмена кода.
const tokens = await oidc.authorizationCodeGrant(config, callbackUrl, {
  pkceCodeVerifier: flow.verifier,
  expectedState: flow.state,
  expectedNonce: flow.nonce,
  idTokenExpected: true
});
const claims = tokens.claims();
if (!claims?.sub || claims.iss !== 'https://id.15reg.ru') {
  throw new Error('Invalid identity');
}
// Найдите связь по (claims.iss, claims.sub), затем создайте
// собственную сессию проекта. Email для объединения не используйте.
// Не печатайте callbackUrl, tokens или flow в лог.
Разрешения и время жизни
ЭлементНазначениеОграничение
openidСтабильный subject существующего аккаунтаОбязателен для OIDC
profileИмя и usernameПосле согласия
emailАдрес и фактический email_verifiedНе основание для автопривязки
offline_accessRefresh tokenДо 30 дней; ротация при каждом использовании
Code / interactionОдноразовый обмен / экран подтверждения60 секунд / 10 минут
ID token / access tokenПодтверждение входа / UserInfo5 минут

Согласие на прежние scopes может использоваться повторно. Новые права требуют нового подтверждения. ID не выдаёт историю переписки или административную роль проекта. ID token, токен бота и cookie социальной сети не заменяют друг друга.

4. Различайте сессии, выход и отзыв
ДействиеРезультат
Выйти из вашего проектаУдаляется локальная сессия проекта. Сессия ID может сохраниться.
Выйти из центра IDRP-initiated logout из discovery с подтверждением на ID-домене. Полный выход отзывает связанную ID-сессию и очищает её cookie.
Отозвать разрешение проектаВ кабинете ID удаляется согласие и связанные серверные артефакты. Новое обращение потребует входа и согласия.
Отключить клиентВладелец запрещает новые входы и использование его серверных артефактов для всех пользователей этого клиента.
Отозвать устройство / сменить парольПрименяется обычное управление сессиями 15reg. Связанные с отозванной сессией protocol artifacts перестают проходить серверную проверку.

Cookie основной соцсети остаётся host-only. ID-домен создаёт отдельную host-only сессию через ту же проверку существующего аккаунта. Поэтому при первом посещении ID может потребоваться пароль; вход в Android сам по себе не создаёт сессию системного браузера.

Уже выданный автономный ID JWT действует до своего expiry. Для завершения сессий внешнего проекта поддерживается OIDC Back-Channel Logout: проверяйте подпись, issuer, audience, время, logout event, отсутствие nonce, sid/sub и одноразовый jti. Пример содержит такой обработчик. Доставка в недоступный проект не является гарантированным мгновенным выходом: сохраняйте ограниченный срок своих сессий и следите за ошибками callback.

5. Нативный Android без WebView

Отдельный проект apps/id-android-example использует AppAuth, системную Custom Tab, PKCE и Android Keystore. Он не содержит secret клиента и не заменяет основной APK 15reg. Сохранённый запрос переживает уничтожение процесса; ответ проверяется против исходного state, client ID и точного redirect.

  1. Зарегистрируйте отдельный android-клиент с HTTPS callback вида https://ваш-проект/oauth/android/callback.
  2. Опубликуйте на своём домене /.well-known/assetlinks.json с package name и SHA-256 сертификата этой сборки.
  3. В apps/id-android-example выполните сборку с реальными client ID и callback host. Для PowerShell используйте .\gradlew.bat.
  4. На устройстве проверьте верификацию App Link, согласие, отмену, смену аккаунта, возврат после уничтожения процесса и повтор callback. Unit-тесты не заменяют проверку браузерного возврата.
[
  {
    "relation": [
      "delegate_permission/common.handle_all_urls"
    ],
    "target": {
      "namespace": "android_app",
      "package_name": "ru.reg15.idexample",
      "sha256_cert_fingerprints": [
        "SHA-256 СЕРТИФИКАТА ИМЕННО ВАШЕЙ СБОРКИ"
      ]
    }
  }
]
./gradlew testDebugUnitTest lintDebug assembleDebug \
  -PID_CLIENT_ID=ваш_client_id -PID_CALLBACK_HOST=ваш-домен

Пример рассчитан на Android 9 и новее. Он запрашивает openid/profile и очищает локальное состояние по кнопке выхода; фоновое обновление токенов в этом примере не реализовано. В Windows устанавливайте PWA через браузер.

6. Запустите готовый внешний пример
# Из корня релизного исходного кода, Node 24:
pnpm install --frozen-lockfile
# Скопируйте apps/id-example/.env.example в .env этой же папки.
# Укажите отдельную БД, ID_CLIENT_ID, LOCAL_USERNAME,
# уникальный LOCAL_PASSWORD (минимум 16 символов).
pnpm --dir apps/id-example migrate
pnpm --dir apps/id-example test
pnpm --dir apps/id-example start
# Откройте http://127.0.0.1:8080; Ctrl+C завершает процесс.

Ожидаемый результат: вход через ID → согласие → собственная сессия внешнего проекта. Затем выйдите только из проекта и войдите повторно: локальная запись должна остаться той же. Для проверки привязки сначала используйте локальную форму входа, повторите локальный пароль и выберите ID. После настройки удалите LOCAL_PASSWORD из .env; в базе остаётся Argon2-хеш.

Пример запускается на loopback и использует отдельную БД. Перед размещением вашего проекта добавьте его собственные лимиты входа, восстановление, аудит и резервирование. Не направляйте пример в production-базу социальной сети.

Ошибки и проверка перед запуском
СитуацияДействие клиента
access_deniedПокажите отказ и кнопку возврата. Не запускайте новый вход автоматически.
invalid_grantCode/refresh истёк, использован или не подходит. Начните новый вход; не повторяйте одноразовый обмен.
invalid_client / invalid_requestПроверьте регистрацию, точный redirect и PKCE. Не принимайте произвольный callback из запроса пользователя.
Неверные state, nonce, issuer, audience, подписьПрервите вход. Не создавайте сессию даже при HTTP 200 от token endpoint.
Сеть пропала после обменаОперация могла состояться. Закройте flow и предложите новый вход вместо автоматического повтора code.
Refresh использован повторноЦепочка отзывается. Исключите параллельное обновление в своём хранилище.

Проверьте успешный и повторный вход, отказ, истечение, неверный verifier/state/nonce, повтор callback, другой client ID, отзыв сессии, привязку существующего аккаунта и невозможность привязать чужой. Не сохраняйте пароли, токены или callback query в access logs, аналитике и отчётах об ошибках.