public_id пользователя. Вы проверяете подпись нашим публичным ключом — так вы знаете, что ссылку сформировали мы и public_id не подменён. Но токен предъявительский: подпись не доказывает, что ссылку открыл тот, кому мы её выдали, — см. Кто открыл ссылку.
Подключение
Вы присылаете адрес виджета и название пункта меню
https:// и на вашем домене, не на домене Ai-Seven. Название пункта меню в кабинете Ai-Seven — до 100 символов.Мы сообщаем значение aud
iss в Partner API — идентификатор вашей интеграции. С ним вы сверяете aud каждого токена.Как это работает
Пользователь открывает страницу виджета
Даёт согласие
public_id к вам не уходит.Мы открываем виджет с токеном
<адрес виджета>?token=<JWT> — во фрейме кабинета или, по кнопке «Открыть в новой вкладке», в отдельной вкладке. Токен выпускается заново при каждом открытии.Вы проверяете токен
Ссылка
token. Если в адресе виджета уже есть параметры, токен добавляется к ним через &: https://partner.example.com/widget?lang=ru&token=....
Формат токена
Заголовок
Payload
iss в Partner API — идентификатор вашей интеграции, который мы сообщаем при подключении. Токен, выпущенный для другого партнёра, вам не подходит.public_id пользователя — тот же, что в статистике. По нему вы выдаёте подписку и доступы.JWKS
Наши публичные ключи — по фиксированному адресу, без авторизации:Проверка токена на вашей стороне
Подпись — только RS256
["RS256"]. Не берите алгоритм из заголовка токена.Ключ — только из нашего JWKS
https://aisevenai.ru/api/v1/partner/.well-known/jwks.json. Не стройте адрес ключей из iss, jku или x5u токена.iss и aud — точное совпадение
iss — точно https://aisevenai.ru, aud — точно ваш iss в Partner API.Срок
exp и iat с допуском на расхождение часов 30–60 секунд. Токен живёт 300 секунд.Кеш JWKS и незнакомый kid
kid нет в закешированном JWKS — перечитайте JWKS, но не чаще раза в минуту.Одноразовость по jti
jti принятого токена до его exp плюс допуск по часам и записывайте атомарно — например, в Redis: SET widget-jti:<jti> 1 NX EXAT <exp+60>. Не записалось — токен уже предъявляли: отклоните его.Сразу обменяйте токен на свою сессию
GET <адрес виджета>?token=…, проверяет токен, ставит сессию и отвечает 303 на тот же адрес без token. Так токен не видят скрипты страницы и он не уходит в Referer.Одностраничное приложение, которое получает токен в браузере, отправляет его на свой сервер в теле POST, а не в адресе, и сразу убирает из адреса только параметр token, сохраняя остальные:Кто открыл ссылку
Токен виджета — предъявительский. Подпись доказывает, что ссылку выпустили мы для этогоpublic_id, но не то, что её открыл тот, кому мы её выдали: пересланная или перехваченная ссылка до exp сработает и у другого человека. Поэтому:
- Показывайте на странице виджета, под кем выполнен вход.
- Если в браузере уже открыта ваша сессия другого
sub, не переключайте её молча: покажите, что пришёл вход под другим пользователем, и спросите, под кем продолжить. - При входе по ссылке в отдельной вкладке, а не во фрейме, просите подтверждение: «Продолжить как
<имя>». На сервере отличайте фрейм от вкладки по заголовкуSec-Fetch-Dest(iframeилиdocument); в браузере — поwindow.self === window.top. - Проверка
Referer— только дополнение к этим мерам, а не замена им.
Пример
remember_jti_or_reject / rememberJtiOrReject — ваше хранилище принятых jti с атомарной записью: например, SET widget-jti:<jti> 1 NX EXAT <until> в Redis. Команда ничего не записала — токен уже предъявляли, отклоните его.
Ротация ключа
Мы меняем ключ подписи на новый, с новымkid, по шагам:
Новый ключ появляется в JWKS
Новый ключ начинает подписывать
Старый ключ убирается из JWKS
Требования к странице виджета
Виджет открывается во фрейме внутри кабинета Ai-Seven, а по кнопке «Открыть в новой вкладке» — в отдельной вкладке, со свежим токеном. Страница должна работать в обоих случаях, и так, чтобы токен не утёк:Разрешите встраивание только нам
Разрешите встраивание только нам
Content-Security-Policy: frame-ancestors https://aisevenai.ru. Заголовок X-Frame-Options: DENY или SAMEORIGIN встраивание запретит.Ограничения фрейма: оплата — в новой вкладке, свои окна, файлы
Ограничения фрейма: оплата — в новой вкладке, свои окна, файлы
sandbox="allow-scripts allow-same-origin allow-forms allow-popups allow-popups-to-escape-sandbox" — других разрешений нет.Навигация верхнего окна запрещена (нет allow-top-navigation): виджет не может увести вкладку Ai-Seven на свой адрес. Оплату, вход и любые свои окна открывайте новой вкладкой — ссылкой с target="_blank" или window.open.Диалоги браузера (alert, confirm, prompt) и скачивание файлов во фрейме не работают. Вместо диалогов показывайте свои окна на странице, файлы открывайте новой вкладкой.Referrer-Policy: no-referrer
Referrer-Policy: no-referrer
Referrer-Policy: no-referrer — иначе адрес с токеном уйдёт в Referer запросов к сторонним ресурсам страницы.Уберите токен из адреса
Уберите токен из адреса
303 на тот же адрес без token. В одностраничном приложении — отправка токена на свой сервер в теле POST и history.replaceState, как в проверке токена. Обновление страницы не должно требовать токена.Не пускайте адрес с токеном в журналы и аналитику
Не пускайте адрес с токеном в журналы и аналитику