Вход через Syndicate

Last updated: 2026-10-29Как дать людям войти в ваше приложение аккаунтом Синдиката — OAuth 2.1 с кодом авторизации и PKCE, scopes, токены, userinfo и самостоятельная проверка токенов.

Вход через Syndicate

У людей уже есть аккаунт Синдиката для Resonance, ASAI, Apeiron и остальной платформы. Ваше приложение может пустить их по нему, без нового пароля. Схема — OAuth 2.1, код авторизации с PKCE.

Заведите клиент

В Dev Studio откройте Sign-in apps и создайте приложение:

  • Название — его человек увидит в окне согласия.
  • Redirect URI — до 10, сверяются точно. Нативному приложению подойдёт loopback-адрес (http://127.0.0.1/callback): порт не сверяется, свободный можно выбрать при запуске.
  • Scopes — что приложение вообще может запросить. Для email и subscription нужно обоснование в заявке разработчика.

client_id (asc_…) выдаётся сразу. Секрет клиента показывается один раз, но эндпоинт токенов его не использует: подлинность клиента держится только на PKCE. Считайте любой клиент публичным и никогда не кладите секрет в браузерный бандл или сборку приложения. На одном аккаунте — до 10 активных клиентов.

Эндпоинты

МетодЭндпоинтЗачем
GEThttps://auth.aperturesyndicate.com/api/v1/sso/authorizeНачать вход в браузере
POSThttps://auth.aperturesyndicate.com/api/v1/sso/tokenОбменять код, обновить токены
GEThttps://auth.aperturesyndicate.com/api/v1/sso/userinfoКто вошёл, с учётом scopes
GEThttps://auth.aperturesyndicate.com/.well-known/jwks.jsonОткрытые ключи для проверки токенов
GEThttps://auth.aperturesyndicate.com/.well-known/oauth-authorization-serverМетаданные RFC 8414

В метаданных перечислены и scopes для ИИ-агентов, которые подключаются к нашему MCP-серверу. Клиент из Dev Studio может запросить только четыре scope ниже.

Scopes

ScopeЧто добавляет в /userinfo
openidsub — постоянный id аккаунта
profilenickname, avatar_url, profile_url
emailemail, email_verified
subscriptionsubscription — действующий тариф и возможности, или null

Внутреннее имя пользователя не раскрывается нигде — ни в /userinfo, ни в токене. Связывайте аккаунты по sub.

1. Отправьте человека на вход

Сгенерируйте случайный code_verifier (43–128 символов) и code_challenge = base64url(SHA-256(verifier)). Затем перенаправьте:

text
https://auth.aperturesyndicate.com/api/v1/sso/authorize
  ?response_type=code
  &client_id=asc_…
  &redirect_uri=https://yourapp.example/callback
  &scope=openid profile
  &state=<случайная строка>
  &code_challenge=<challenge>
  &code_challenge_method=S256
Параметр
response_typeВсегда code
client_idИз Dev Studio
redirect_uriОдин из заведённых
scopeЧерез пробел, в пределах scopes клиента
stateОбязателен. Сверьте его на обратном пути
code_challenge_methodТолько S256; plain отклоняется
promptНеобязателен. none не показывает никаких экранов и возвращает error=login_required, если человек не вошёл
screenНеобязателен. register ведёт невошедшего человека на создание аккаунта, а не на вход

Невошедший человек сначала входит. Потом он всегда видит окно согласия с названием вашего приложения и scopes: стороннее приложение никогда не получает код молча. Если человек согласился, браузер вернётся на:

text
https://yourapp.example/callback?code=…&state=…

Код живёт 10 минут и срабатывает один раз. При отказе или сбое в адресе будет error — с prompt=none это login_required или consent_required.

2. Обменяйте код

bash
curl -X POST https://auth.aperturesyndicate.com/api/v1/sso/token \
  -H "content-type: application/json" \
  -d '{
    "grant_type": "authorization_code",
    "client_id": "asc_…",
    "code": "…",
    "redirect_uri": "https://yourapp.example/callback",
    "code_verifier": "…"
  }'
json
{
  "access_token": "eyJ…",
  "refresh_token": "…",
  "token_type": "Bearer",
  "expires_in": 900,
  "scope": "openid profile"
}

Эндпоинт принимает JSON или application/x-www-form-urlencoded. Запрос формой получает ошибки в формате RFC 6749 ({"error":"invalid_grant","error_description":"…"}), запрос в JSON — {"error":"…","code":"…"}.

3. Обновление

Access-токен живёт 15 минут, refresh-токен — 30 дней. Каждое обновление выдаёт новый refresh-токен: сохраните его, а старый выбросьте.

json
{ "grant_type": "refresh_token", "client_id": "asc_…", "refresh_token": "…" }

Refresh-токен годится только тому клиенту, которому выдан. Если человек вышел на всех устройствах, заблокирован или удалил аккаунт, обновление не пройдёт, и ему придётся войти заново.

4. Кто вошёл

bash
curl https://auth.aperturesyndicate.com/api/v1/sso/userinfo \
  -H "Authorization: Bearer eyJ…"
json
{
  "sub": "5f0c…",
  "nickname": "Nova",
  "avatar_url": "https://…",
  "profile_url": "https://aperturesyndicate.com/u/nova",
  "email": "…",
  "email_verified": true
}

Со scope subscription:

json
"subscription": {
  "plan": "PREMIUM",
  "status": "ACTIVE",
  "features": ["lq"],
  "items": [],
  "current_period_end": "2026-11-29T00:00:00.000Z",
  "cancel_at_period_end": false
}

Проверяйте features, а не plan — plan оставлен для старых клиентов. status равен CANCELLED, если подписка дорабатывает период и не продлится.

Проверка токена у себя

Access-токен — JWT на RS256. Проверяйте его по JWKS, а не вызовом /userinfo на каждый запрос:

Поле
isshttps://auth.aperturesyndicate.com
audas-third-party и ваш client_id — токен без вашего client_id отклоняйте
subId аккаунта
nicknameОтображаемое имя на момент выдачи
scopesВыданные scopes
exp, iatСрок и время выдачи

Токен, выданный вашему приложению, открывает только /userinfo. Это не ключ к плейлистам человека, ASAI или чему-то ещё на платформе.

Ошибки

КодГдеЗначит
INVALID_REQUESTобаПараметра нет или он неверный, в том числе PKCE plain
INVALID_CLIENTобаНеизвестный или отключённый client_id
INVALID_REDIRECT_URIобаНе заведён или отличается от того, что был в шаге 1
auth.state.missingauthorizeНе передан state
INVALID_CODEtokenКод истёк, использован или выдан другому клиенту
PKCE_FAILEDtokencode_verifier не совпадает с challenge
INVALID_SCOPEtokenScope вне списка клиента
INVALID_TOKENtokenRefresh-токен истёк или отозван
INVALID_GRANTtokenRefresh-токен принадлежит другому клиенту
ACCOUNT_BANNEDtoken403; все сессии аккаунта закрыты
MISSING_TOKEN, TOKEN_REVOKEDuserinfo401 — нет токена или человек вышел
Вход через Syndicate | AS Docs