login.tj

Документация · production

login.tj

Официальный issuer: https://login.tj (sandbox: https://sandbox.login.tj). Единый вход по OpenID Connect (Authorization Code + PKCE). Общей cookie между сайтами нет — каждый RP ходит на этот issuer: https://login.tj.

Быстрый старт

  1. Зарегистрируйте приложение в кабинете разработчика (нужен аккаунт на этом issuer). Получите client_id; у web — секрет один раз.
  2. Whitelist: добавьте точные redirect_uri / logout URI. В production заявка сначала pending, пока модератор не одобрит.
  3. Wizard «Подключить сайт» на странице клиента в /dev — готовые .env, код и кнопка Проверить вход (self-test OIDC).
  4. На вашем сайте маршрут входа строит Authorization URL с PKCE (state, nonce, code_challenge) и редиректит пользователя на https://login.tj/auth.
  5. Callback: обменяйте code на токены на https://login.tj/token, проверьте id_token (iss, aud, exp, nonce). Стабильный id — UUID sub.

Демо-клиент этого стенда: apps/demo-client (обычно порт 4000) · вход на IdP: /login

Discovery

Метаданные: https://login.tj/.well-known/openid-configuration. Поле environment: production, sandbox или development.

  • authorization: https://login.tj/auth
  • token: https://login.tj/token (client_secret_basic или none для SPA/native)
  • userinfo: https://login.tj/me
  • jwks: https://login.tj/jwks
  • end_session: https://login.tj/session/end
  • revocation: https://login.tj/token/revocation

Клиент

Типы в /dev: web (confidential, секрет) и SPA/native (публичные, только PKCE, token_endpoint_auth_method=none). redirect_uri — точное совпадение со списком.

  • grant: authorization_code; refresh_token только у confidential web
  • PKCE обязателен (S256)
  • scopes: openid, profile, email, phone; offline_access — только confidential
  • идентификатор пользователя — UUID sub, не email
  • email/phone в токене только если контакт подтверждён
  • вход и SSO только после подтверждения email или телефона
  • MFA для RP: запросите acr_values=urn:login.tj:mfa — IdP не завершит вход с acr=pwd; без TOTP/passkey у пользователя будет access_denied. Backup-коды на этом пути не принимаются. RP обязан проверять acr в id_token

Условия API

Кнопка «Войти через login.tj»

На сайте пользователя ссылка ведёт на ваш маршрут (например /auth/logintj), который собирает Authorization URL с PKCE — не на голый https://login.tj/auth без параметров. Стили: https://login.tj/assets/login-button.css (или скопируйте файл). Пример в репозитории: examples/login-button/.

<link rel="stylesheet" href="https://login.tj/assets/login-button.css" />
<a class="login-tj-btn" href="/auth/logintj">
  <span class="login-tj-btn__mark" aria-hidden="true"></span>
  Войти через login.tj
</a>

Ниже — только внешний вид кнопки. Ссылка ведёт на вход IdP (не на ваш RP).

Claims и токены

В id_token / UserInfo ожидайте как минимум:

  • sub — UUID аккаунта (ключ связи в вашей БД)
  • iss, aud, exp, iat; при запросе — nonce
  • email / email_verified, phone_number / phone_number_verified — только после verify
  • при MFA: acr=urn:login.tj:mfa, amr включает otp или hwk — проверяйте claim на стороне RP, не полагайтесь только на запрос acr_values

Выход

  • RP-initiated: редирект на end_session с client_id, post_logout_redirect_uri (из whitelist) и желательно id_token_hint.
  • Back-channel (confidential): укажите backchannel_logout_uri — IdP пришлет logout token, когда сессия на issuer завершится.

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

  • invalid_client — клиент pending / disabled / banned или неверный секрет
  • redirect_uri mismatch — URI не совпал посимвольно с whitelist
  • invalid_grant — просрочен/повторно использован code, неверный PKCE verifier
  • нет email в токене — контакт не подтверждён кодом
  • в production на формах IdP может требоваться Cloudflare Turnstile

Окружения

Sandbox и production — разные issuer (другой хост/БД/JWKS/client_id). Пользователей и секреты между ними не переносят. Текущая среда: production. Боевой sandbox обычно https://sandbox.login.tj.

Операторам: выкладка и секреты — в репозитории deploy/CUTOVER.md, не на этой странице.

SDK

  • Node: @login.tj/client — после публикации npm install @login.tj/client; пока в monorepo: packages/client, пример examples/node-client/, демо apps/demo-client
  • Laravel: login-tj/laravel — после Packagist composer require login-tj/laravel; пока path-репозиторий: packages/laravel, пример examples/laravel-client/

Кабинет разработчика · Условия API · OpenID Discovery