Авторизация Frontend'ов Плагинов
Эта страница описывает browser-авторизацию для frontend'ов и admin UI плагинов. Для вызова HTTP-trigger API используется user_session; для доступа к встроенному frontend'у плагина под /plugins/* дополнительно требуется admin_session.
Рекомендуемая модель - загружать WASM и frontend одним ZIP bundle. Host сам раздаёт frontend на том же origin, что и Core:
https://<host>/plugins/<plugin-id>/app/В этом режиме browser-куки являются first-party cookies, не нужен CORS, и redirect после ТГУ-входа возвращает пользователя обратно в страницу плагина.
Когда Использовать
Используйте этот сценарий, если плагину нужен собственный веб-интерфейс:
- личный кабинет пользователя
- форма настройки, доступная определённой группе пользователей
- HTML/admin-страница плагина, которая вызывает HTTP-trigger API этого же плагина
Если речь про встроенную админку SuperBotGo (/admin/*), используйте системную admin auth.
Модели Размещения
Bundle На Том Же Origin
Frontend кладётся в ZIP рядом с plugin.wasm:
schedule-plugin.zip
├── plugin.wasm
└── frontend/
├── index.html
├── app.js
└── styles.cssПосле установки host раздаёт его по адресу:
/plugins/<plugin-id>/app/Особенности:
- страницу
/plugins/<plugin-id>/app/может открыть только пользователь сadmin_session - HTTP-trigger API вызывается с
user_session - вход в системную админку через email/password или ТГУ ставит обе cookie:
admin_sessionиuser_session - если
user_sessionистекла или отсутствует, frontend может запустить ТГУ browser login return_toдля bundled frontend должен быть относительным path, а не абсолютным URL
Внешний Frontend
Отдельное приложение на другом origin всё ещё возможно, например:
https://schedule.example.com
http://localhost:5173Для такого режима нужно явно добавить origin в настройках плагина: Frontend origins плагина. HTTP-trigger'ы наследуют этот список. Override на конкретном HTTP-trigger нужен только когда отдельная точка должна принимать другой список origins.
Для cross-origin fetch обязательно:
await fetch('https://bot.example.com/api/triggers/http/my-plugin/profile', {
credentials: 'include',
})В продакшене для cross-site cookies обычно нужен SameSite=None; Secure, поэтому внешний frontend сложнее в эксплуатации. Если frontend можно поставить рядом с Core, используйте bundle на том же origin.
Поток Login
Контракт Frontend'а
Старт Логина В Bundled Frontend
Используйте относительный return_to. Это важно: absolute URL вида http://127.0.0.1:4000/plugins/schedule/app/ может быть обработан как внешний redirect и отклонён, если origin не разрешён как внешний frontend.
const returnTo = location.pathname + location.search + location.hash
window.location.href = `/api/auth/tsu/start?return_to=${encodeURIComponent(returnTo)}`Host дополнительно умеет нормализовать same-origin absolute URL в локальный path, но относительный return_to остаётся предпочтительным контрактом.
Минимальная login-страница для bundled frontend:
export function LoginPage() {
const login = () => {
const returnTo = location.pathname + location.search + location.hash
location.href = `/api/auth/tsu/start?return_to=${encodeURIComponent(returnTo)}`
}
return (
<main>
<h1>Вход</h1>
<button type="button" onClick={login}>
Войти через ТГУ
</button>
</main>
)
}После callback host поставит user_session и вернёт браузер на тот же URL. Если страница плагина открывается только администраторам, пользователь обычно уже имеет admin_session; user_session нужна frontend'у для HTTP-trigger API.
Старт Логина Во Внешнем Frontend
Для внешнего frontend'а можно передать полный URL, но его origin должен быть зарегистрирован в Frontend origins плагина.
const returnTo = location.href
window.location.href =
`https://bot.example.com/api/auth/tsu/start?return_to=${encodeURIComponent(returnTo)}`Проверка текущей host-сессии:
const res = await fetch('/api/auth/session', { credentials: 'include' })
const session = await res.json()Вызов HTTP-trigger endpoint'а:
await fetch('/api/triggers/http/my-plugin/profile', {
method: 'GET',
credentials: 'include',
})Logout:
await fetch('/api/auth/logout', {
method: 'POST',
credentials: 'include',
})Настройка HTTP-trigger
Host проверяет доступ до вызова wasm-плагина. Для browser-сценария включите у trigger'а:
allow user session- при необходимости
policy expression
Если allow user session выключен, user_session не даст доступ к endpoint'у, даже если пользователь успешно вошёл через ТГУ.
Если frontend плагина должен быть доступен только администраторам, закрывайте саму страницу через bundled hosting под /plugins/<plugin-id>/app/ и дополнительно задавайте policy на HTTP-trigger'ах. admin_session открывает страницу, но API плагина всё равно проходит через обычный HTTP-trigger access check.
Внутри плагина auth-контекст приходит как ctx.HTTP.Auth:
if ctx.HTTP.Auth == nil || ctx.HTTP.Auth.Kind != "user" {
ctx.JSON(401, map[string]string{"error": "authentication required"})
return nil
}
ctx.JSON(200, map[string]any{
"user_id": ctx.HTTP.Auth.UserID,
})Навигация И Redirect
Если пользователь открывает защищённый HTML-trigger обычной навигацией браузера и ещё не вошёл, host делает redirect на:
/api/auth/tsu/start?return_to=<текущий-path-and-query>Для API/fetch-запросов host не редиректит, а возвращает 401, чтобы frontend мог сам показать экран входа.
Если после login пользователь возвращается на /, почти всегда причина в некорректном return_to:
- bundled frontend передал абсолютный URL вместо относительного path
- внешний frontend не добавлен в
Frontend origins плагина - локально смешаны разные host'ы, например
localhostи127.0.0.1
Для локальной проверки используйте один и тот же host во всех URL, например только http://127.0.0.1:4000.
User Bearer Token
Для небраузерных клиентов можно выпустить user bearer token из уже существующей user_session:
POST /api/auth/tokens
Content-Type: application/json
Cookie: user_session=...
{"name":"CLI token"}Дальше HTTP-trigger вызывается так:
Authorization: Bearer sbuk_<public>.<secret>Такой token даёт principal user и проходит через те же настройки trigger'а и policy expression.
Что Не Нужно Делать
- Не используйте
admin_sessionкак principal для HTTP-trigger API плагина. Она только открывает hosted frontend под/plugins/*. - Не храните TSU token во frontend'е.
- Не используйте service-key в браузере: service-key предназначен для server-to-server интеграций.
- Не считайте вход через ТГУ правом доступа: доступ задаётся настройками trigger'а и policy.