Компонент аккаунта REGOS

Компонент аккаунта REGOS добавляет на сайт аватар пользователя и меню профиля. Интерфейс загружается с домена REGOS внутри iframe и получает данные пользователя, авторизованного в вашем приложении. Подключение доступно через JavaScript и React.

Возможности

  • Отображение имени и аватара пользователя.
  • Переход в профиль REGOS по нажатию на аватар или имя пользователя.
  • Подключение устройства, когда эта функция доступна в REGOS.
  • Выбор другого профиля и добавление профиля через авторизацию REGOS.
  • Вход и выход из вашего приложения.
  • Светлая, тёмная и системная темы, 14 языков, адаптация для мобильных устройств.

На компьютере меню открывается справа сверху, на телефоне — в виде нижней панели. Меню поддерживает клавиатуру, закрытие по Escape и возвращение фокуса к кнопке аккаунта. Обновления интерфейса REGOS появляются при следующей загрузке компонента.

В основном меню доступны «Сменить профиль», «Подключить устройство» с иконкой QR-кода и «Выйти из приложения». Аватар и имя образуют единую ссылку на профиль. В профиле доступны редактирование данных, уведомления, безопасность и остальные настройки аккаунта.

Подготовка

  1. Зарегистрируйте OAuth-приложение REGOS и получите clientId.
  2. Добавьте Redirect URI вашего приложения. Origin сайта — схема, домен и порт — должен совпадать с origin зарегистрированного Redirect URI.
  3. Настройте авторизацию пользователя с областями доступа openid profile.
  4. Подготовьте серверный endpoint своего приложения для выдачи разрешения на показ профиля. Его контракт описан ниже.
  5. Подготовьте обработчики входа, выхода, смены и добавления профиля.

Для рабочего сайта используйте HTTPS. Для локальной разработки поддерживается HTTP на loopback-адресах, например http://localhost:3000.

Подключение JavaScript

Добавьте контейнер и скрипт SDK:

<div id="regos-account"></div>
<script
  src="https://auth.regos.uz/widget/regos-account/hosted/1.0.1/sdk.js"
  crossorigin="anonymous"></script>

После загрузки скрипта создайте компонент:

const account = RegosAccountHosted.mount(
  document.querySelector('#regos-account'),
  {
    clientId: 'YOUR_CLIENT_ID',
    locale: 'ru',
    theme: 'system',
    showName: false,

    async getTicket({channel, signal}) {
      const response = await fetch('/api/regos/account-ticket', {
        method: 'POST',
        credentials: 'same-origin',
        headers: {
          'Content-Type': 'application/json',
          'X-CSRF-Token': csrfToken,
        },
        body: JSON.stringify({channel}),
        signal,
      });
      if (response.status === 401) return null;
      if (!response.ok) throw new Error('Не удалось загрузить аккаунт');
      return (await response.json()).ticket;
    },

    async onSignIn() {
      await applicationAuth.signIn();
    },
    async onSignOut() {
      await applicationAuth.signOut();
    },
    async onSwitchAccount({prompt, uiLocales}) {
      await applicationAuth.authorize({prompt, ui_locales: uiLocales});
    },
    async onAddAccount({prompt, uiLocales}) {
      await applicationAuth.authorize({prompt, ui_locales: uiLocales});
    },
    onError(error) {
      showAccountError(error);
    },
  },
);

В примере /api/regos/account-ticket, csrfToken, applicationAuth и showAccountError обозначают endpoint, CSRF-токен и функции вашего приложения. Замените их своей реализацией. Вызовите mount после добавления контейнера в документ.

Для ESM используйте именованный экспорт с теми же параметрами:

import {mountRegosAccount} from
  'https://auth.regos.uz/widget/regos-account/hosted/1.0.1/sdk.mjs';

const account = mountRegosAccount(container, options);

Получение разрешения на показ профиля

При вызове getTicket сервер вашего приложения определяет текущего пользователя по своей сессии и получает его действующий access token REGOS. Значения clientId и parentOrigin берутся из серверной конфигурации; значение channel приходит от SDK.

Отправьте серверный запрос:

POST https://auth.regos.uz/account-widget/ticket
Authorization: Bearer ACCESS_TOKEN_OF_CURRENT_USER
Content-Type: application/json

{
  "clientId": "YOUR_CLIENT_ID",
  "parentOrigin": "https://your-site.example",
  "channel": "CHANNEL_FROM_SDK"
}
Поле Описание
clientId Идентификатор приложения, которому выдан access token.
parentOrigin Origin страницы с компонентом, например https://your-site.example.
channel Значение из текущего вызова getTicket.

Успешный ответ:

{
  "ticket": "ONE_TIME_TICKET",
  "expires_in": 30
}

Верните ответ браузеру с заголовком Cache-Control: no-store, а из getTicket верните строку ticket. Разрешение действует 30 секунд и используется один раз. Получайте новое разрешение при каждом вызове getTicket.

REGOS проверяет пользователя, приложение, области доступа openid profile и origin сайта.

HTTP-статус Значение
200 Разрешение выдано.
400 Проверьте поля запроса, активность приложения и регистрацию origin.
401 Требуется действующий пользовательский access token с нужными областями доступа.
5xx Ошибка сервиса; предусмотрите повторную попытку.

Endpoint вашего сайта должен проверять собственную сессию и CSRF-токен. Для гостя возвращайте 401, который getTicket преобразует в null. Ошибки обращения к REGOS обрабатывайте отдельно: обновите истёкший access token своим механизмом авторизации или сообщите об ошибке загрузки. Храните access token на серверной стороне; браузеру возвращайте только разрешение ticket.

Вход, выход и смена профиля

Все четыре обработчика обязательны:

Обработчик Действие приложения
onSignIn() Выполнить вход пользователя.
onSignOut() Завершить сессию пользователя в приложении.
onSwitchAccount({prompt, uiLocales}) Запустить OAuth с prompt=select_account и переданным языком.
onAddAccount({prompt, uiLocales}) Запустить OAuth с prompt=login и переданным языком.

На экране смены профиля компонент показывает текущий аккаунт и действия выбора или добавления профиля. Сохранённые на устройстве аккаунты доступны на штатном экране выбора REGOS, открываемом вашим OAuth-потоком в отдельном окне или через перенаправление. REGOS выполняет необходимые подтверждения, включая запрос пароля согласно настройкам аккаунта.

Используйте Authorization Code Flow с PKCE и проверку ответа OAuth/OIDC. Для нового запроса создавайте соответствующие state, PKCE verifier/challenge и nonce. После успешной авторизации обновляйте сессию приложения и завершайте Promise обработчика. Компонент затем получает актуальный профиль. При отмене выбора сохраняйте прежнюю сессию; ошибку можно передать через отклонённый Promise.

При входе через перенаправление создайте компонент заново на странице возврата. Если пользователь сменился в другой части приложения, вызовите account.refresh().

Профиль и подключение устройства открываются в новой вкладке. REGOS проверяет соответствие аккаунта пользователю приложения и при необходимости предлагает выбрать профиль или войти. Управление сохранёнными профилями и настройка запроса пароля доступны в интерфейсе REGOS.

Параметры подключения

Параметр Описание
clientId Обязательный идентификатор OAuth-приложения.
getTicket(context) Обязательная асинхронная функция. Возвращает строку разрешения или null для гостя. В context передаются clientId, parentOrigin, channel и signal.
onSignIn, onSignOut, onSwitchAccount, onAddAccount Обязательные обработчики действий с сессией.
locale Язык интерфейса. По умолчанию используется html.lang, затем язык браузера.
theme light, dark или system. По умолчанию system.
showName Показывать имя рядом с аватаром. По умолчанию false.
origin Адрес размещения REGOS. По умолчанию https://auth.regos.uz.
styleNonce Nonce для stylesheet компонента при использовании CSP.
onError(error) Обработчик ошибок загрузки и действий с сессией.

Поддерживаемые языки: ru, en, uz, zh, kk, ky, uk, be, tg, tr, ka, az, hy, ko. Для остальных значений используется русский язык.

Методы компонента

mount(container, options) возвращает объект:

Метод Назначение
open() Открыть меню.
close() Закрыть меню.
refresh() Получить актуальный контекст пользователя через новый вызов getTicket.
update({locale, theme, showName}) Обновить оформление.
destroy() Удалить компонент и освободить его ресурсы. Вызывайте при удалении страницы или блока приложения.
account.update({theme: 'dark', locale: 'en'});
account.refresh();

// При удалении блока приложения:
account.destroy();

Получение разрешения и запуск iframe имеют таймаут 15 секунд. Используйте onError, чтобы показать сообщение и предложить повторную попытку через refresh().

Подключение React

React-обёртка поддерживает React 18 и 19. Скопируйте из каталога https://auth.regos.uz/widget/regos-account/hosted/1.0.1/ файлы sdk.mjs и react.mjs в один каталог проекта. Для TypeScript также добавьте sdk.d.mts, sdk.d.ts, react.d.mts и react.d.ts.

import {RegosHostedAccount} from './regos-account-hosted/react.mjs';

<RegosHostedAccount
  clientId="YOUR_CLIENT_ID"
  locale="ru"
  theme="system"
  getTicket={getAccountTicket}
  onSignIn={signIn}
  onSignOut={signOut}
  onSwitchAccount={switchAccount}
  onAddAccount={addAccount}
  onError={handleError}
/>

Функции в примере реализуются по тому же контракту, что и в JavaScript-подключении. Обёртка принимает параметры подключения и дополнительный className для контейнера. Подключайте её через сборщик проекта с установленным React.

Используйте стабильные callbacks, например useCallback. При смене сессии обновите getTicket callback, чтобы компонент загрузил актуальный профиль. Обёртка автоматически освобождает ресурсы при unmount, поддерживает StrictMode и начинает загрузку после клиентского монтирования при SSR.

Настройка сайта

В Content Security Policy сайта разрешите:

  • script-src https://auth.regos.uz — загрузку SDK с REGOS.
  • frame-src https://auth.regos.uz — размещение интерфейса аккаунта.
  • В connect-src — обращение к endpoint выдачи разрешения вашего сайта.
  • В style-src — nonce, переданный в styleNonce, либо принятую в вашем приложении политику inline styles.

Для Subresource Integrity используйте SHA-384 из файла integrity.json выбранной версии SDK и атрибут crossorigin="anonymous" у скрипта.

Закрепляйте версию SDK в URL подключения. При обновлении версии проверяйте обработчики сессии, оформление и настройки CSP вашего сайта.

??? ??????????? ?????? ???????? ????????? ?? DOM-??????? ? anchorElement ? ????????? account.open() ??? ???????. ???? ????????????? ???????????? ???? ??????; ????? ???????? ????? ???????????? ?? ???.

?????? ???????? ?????????? ??????: 48 px ? ?????????? ?????? ? 240 px ??? showName: true. ?????????? ????? ?????????? ??????, ?????? ????? ??? ??????. ??????? ??? ??????????? ???????????; ???????? ? ????? ????????? ????????? ??????.

?? ????????? ?????? ??????????? ??????????? ????????? ?????? QR ? ??????? ???????. ????? ????????? ????????????? ?????? ?????????? ???????????? ?? ???????? ????????. ???????? ???? ?????????? ? ??????????? ?????? ???????? ????? ??????????? ?????????? (DeviceVerificationReturnUris) ? ?????????? OAuth-???????.