Документация · production
login.tj
Официальный issuer: https://login.tj (sandbox: https://sandbox.login.tj).
Единый вход по OpenID Connect (Authorization Code + PKCE). Общей cookie между сайтами нет —
каждый RP ходит на этот issuer: https://login.tj.
Быстрый старт
-
Зарегистрируйте приложение в
кабинете разработчика (нужен аккаунт на этом issuer).
Получите
client_id; у web — секрет один раз. -
Whitelist: добавьте точные
redirect_uri/ logout URI. В production заявка сначалаpending, пока модератор не одобрит. -
Wizard «Подключить сайт» на странице клиента в
/dev — готовые
.env, код и кнопка Проверить вход (self-test OIDC). -
На вашем сайте маршрут входа строит Authorization URL с PKCE
(
state,nonce,code_challenge) и редиректит пользователя наhttps://login.tj/auth. -
Callback: обменяйте
codeна токены наhttps://login.tj/token, проверьтеid_token(iss,aud,exp,nonce). Стабильный id — UUIDsub.
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
Кнопка «Войти через 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).
Войти через login.tj Светлый вариант
Claims и токены
В id_token / UserInfo ожидайте как минимум:
sub— UUID аккаунта (ключ связи в вашей БД)iss,aud,exp,iat; при запросе —nonceemail/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 не совпал посимвольно с whitelistinvalid_grant— просрочен/повторно использован code, неверный PKCE verifier- нет email в токене — контакт не подтверждён кодом
- в production на формах IdP может требоваться Cloudflare Turnstile
Окружения
Sandbox и production — разные issuer (другой хост/БД/JWKS/client_id).
Пользователей и секреты между ними не переносят. Текущая среда: production.
Боевой sandbox обычно https://sandbox.login.tj.
SDK
-
Node:
@login.tj/client— после публикацииnpm install @login.tj/client; пока в monorepo:packages/client, примерexamples/node-client/, демоapps/demo-client -
Laravel:
login-tj/laravel— после Packagistcomposer require login-tj/laravel; пока path-репозиторий:packages/laravel, примерexamples/laravel-client/