Авторизация и токены

Всё, что не является публичным каталогом поселков, требует токена. Токен передаётся заголовком:

Authorization: Bearer <токен>

Токенов два вида, и выбор между ними — это выбор, чей это доступ.

Личный токен: ваш собственный скрипт

Заводится в Настройки → Доступ к MCP, показывается один раз при создании и больше никогда: хранится только его хэш. Потеряли — заведите новый.

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

Срок жизни задаётся при создании, по умолчанию год. Варианта «бессрочно» нет, и это честность, а не строгость: Passport ставит срок каждому токену, поэтому интерфейс, обещающий вечность, обещал бы то, чего хранилище не делает.

OAuth: приложение для других людей

Если вы делаете приложение, которым будут пользоваться другие жители, токен должен выдавать не человек копипастом, а сервер после явного согласия.

Стандартный authorization_code с обязательным PKCE:

Метаданные сервера GET /.well-known/oauth-authorization-server
Метаданные ресурса GET /.well-known/oauth-protected-resource/mcp/{аудитория}
Экран согласия GET /oauth/authorize
Обмен кода на токен POST /oauth/token

PKCE обязателен, а не желателен: клиент, который нельзя научить хранить секрет — а браузерное приложение и десктопный ассистент именно такие, — без PKCE отдаёт аккаунт любому, кто перехватил код авторизации.

Метаданные ресурса спрашивайте про конкретный сервер. Серверов несколько, по одному на аудиторию, поэтому документ у каждого свой: /.well-known/oauth-protected-resource/mcp/resident. Без пути отдаётся резидентский сервер — тот, до которого дотягивается любой аккаунт.

Читайте метаданные, а не хардкодьте адреса: они строятся от того хоста, на который пришёл запрос, а у поселка может быть свой поддомен.

Откуда взять client_id

Два способа, и выбирать вам.

Client ID Metadata Documents — предпочтительный. Вы размещаете у себя JSON-документ и присылаете его адрес как client_id:

{
  "client_id": "https://ваш-домен/oauth/client.json",
  "client_name": "Название, которое увидит человек",
  "redirect_uris": ["http://127.0.0.1:3000/callback"]
}

Обязательны три поля: client_id, client_name, redirect_uris. client_id внутри документа должен точно совпадать с адресом, по которому он лежит — это то, что связывает документ с идентификатором, и несовпадение мы отвергаем. Адрес обязан быть https и иметь путь.

Регистрироваться не нужно вовсе, и идентификатор переносим: у поселка свой поддомен, то есть свой сервер авторизации, — с CIMD один и тот же client_id работает во всех.

Мы забираем документ при первой авторизации и кэшируем, уважая ваши заголовки кэширования. Поменяли список адресов — поставьте короткий max-age или no-store, и изменение подхватится.

Динамическая регистрация — запасной. Если CIMD вы не умеете:

POST /oauth/register
{"client_name": "Название", "redirect_uris": ["http://127.0.0.1:3000/callback"],
 "application_type": "native"}

В ответ придёт client_id. Секрет не выдаётся: клиент MCP не умеет его хранить, и вместо него работает PKCE. Спецификация называет этот способ устаревшим, поэтому он здесь для совместимости, а не как рекомендация.

Куда мы согласны вас вернуть. И тот и другой способ проверяют redirect_uris по белому списку. Локальные адреса разрешены — 127.0.0.1, localhost, [::1] с любым портом, — потому что настольный клиент принимает код именно там. Своя схема (ваш-клиент://) добавляется по запросу: напишите нам, какая.

Человек видит ваше приложение в списке разрешённых и может отозвать доступ целиком, одним действием, не разбираясь с отдельными токенами.

Время жизни

Access-токен живёт сутки, refresh-токен — 30 дней. Это и есть смысл OAuth: утёкший access-токен протухает сам, без вашего участия.