AACWorkflow Docs

MCP OAuth 2.1 Авторизация

Постройте OAuth 2.1 сервер авторизации для MCP клиентов с PKCE, ротацией refresh токенов и управлением scope доступом.

AACWorkflow предоставляет свой API через MCP (Model Context Protocol) с OAuth 2.1 авторизацией. Внешние MCP клиенты — включая Claude, ChatGPT коннекторы и пользовательские инструменты — аутентифицируются через OAuth сервер чтобы получить scopт-скопированные, обновляемые токены доступа привязанные к паре (пользователь, workspace).

Обзор

OAuth сервер реализует Authorization Code grant с PKCE (Proof Key for Code Exchange), ротацией refresh токенов и динамической регистрацией клиентов. Это обеспечивает:

  • Контроль пользователя — пользователи явно предоставляют доступ к workspace через экран согласия
  • Scope-базированный доступ — клиенты объявляют какие ресурсы им нужны (issues, комментарии, агенты и т.д.)
  • Жизненный цикл токена — короткоживущие токены доступа (~15 мин) и обновляемые долгоживущие токены
  • Обнаружение переиспользования — повтор refresh токена отзывает всю семью токенов, обнаруживая утечки токенов

OAuth поток

1. Регистрация клиента

Клиенты регистрируют себя один раз через:

POST /oauth/register
Content-Type: application/json

{
  "client_name": "My MCP Tool",
  "redirect_uris": ["http://localhost:5000/callback"],
  "grant_types": ["authorization_code", "refresh_token"],
  "token_endpoint_auth_method": "none"
}

Возвращает client_id и client_secret (или нет secret для public клиентов).

2. Authorization code поток

Клиент инициирует логин:

GET /oauth/authorize?
  client_id=<id>&
  redirect_uri=http://localhost:5000/callback&
  response_type=code&
  scope=issues:read+issues:write+comments:read&
  code_challenge=<sha256_hash>&
  code_challenge_method=S256

Пользователь видит экран согласия со списком запрашиваемых scope и workspace для доступа. При одобрении они получают auth код (действителен 10 минут):

HTTP 302
Location: http://localhost:5000/callback?code=<auth_code>&state=<state>

3. Обмен кода на токен

POST /oauth/token
Content-Type: application/x-www-form-urlencoded

grant_type=authorization_code&
code=<auth_code>&
client_id=<id>&
code_verifier=<original_plain_challenge>&
redirect_uri=http://localhost:5000/callback

Возвращает:

{
  "access_token": "eyJ0eXAiOiJKV1QiLCJhbGc...",
  "token_type": "Bearer",
  "expires_in": 900,
  "refresh_token": "<refresh_token>",
  "scope": "issues:read issues:write comments:read"
}

Access токен — это подписанный JWT содержащий:

  • sub — ID пользователя
  • wsid — ID workspace'а
  • scope — space-delimited scopes
  • exp — expiration (900 секунд)

4. Refresh токен ротация

Когда access токен expiration, используйте refresh токен:

POST /oauth/token
Content-Type: application/x-www-form-urlencoded

grant_type=refresh_token&
refresh_token=<refresh_token>&
client_id=<id>

Возвращает новый access токен и новый refresh токен. Старый refresh токен автоматически инвалидируется. Если старый refresh токен повторно использован, сервер отзывает всю семью токенов, сигнализируя возможную утечку.

Scopes

Scope токены определяют какие ресурсы клиент может получить доступ:

ScopeДоступ
issues:readЧитать issues, статус, timeline
issues:writeСоздавать, обновлять issues; менять статус
comments:readЧитать комментарии issue и потоки
comments:writeСоздавать и редактировать комментарии
agents:readСписок агентов, просмотр деталей
agents:writeСоздавать агентов, назначать на issues
runtimes:readЗапрос статуса runtime и логов
autopilot:runАктивировать autopilots
dashboard:readЗапрос дашбордов использования и качества

Клиенты запрашивают подмножество scopes во время авторизации. Токен выдаётся только с запрашиваемыми scopes. Если refresh сужает scopes, новый токен несёт меньше scopes чем оригинал.

Endpoints

MethodPathЦель
GET/.well-known/oauth-authorization-serverRFC 8414 метаданные discovery
GET/oauth/authorizeUI согласия; выдаёт auth codes
POST/oauth/tokenCode-to-token и refresh потоки
POST/oauth/registerДинамическая регистрация клиента (RFC 7591)
POST/oauth/revokeRFC 7009 отзыв токена

Discovery

Клиенты могут обнаружить метаданные сервера авторизации:

GET /.well-known/oauth-authorization-server

Возвращает:

{
  "issuer": "https://aacworkflow.example.com",
  "authorization_endpoint": "https://aacworkflow.example.com/oauth/authorize",
  "token_endpoint": "https://aacworkflow.example.com/oauth/token",
  "registration_endpoint": "https://aacworkflow.example.com/oauth/register",
  "revocation_endpoint": "https://aacworkflow.example.com/oauth/revoke",
  "scopes_supported": [
    "issues:read", "issues:write", "comments:read", "comments:write",
    "agents:read", "agents:write", "runtimes:read", "autopilot:run", "dashboard:read"
  ],
  "response_types_supported": ["code"],
  "grant_types_supported": ["authorization_code", "refresh_token"],
  "token_endpoint_auth_methods_supported": ["none"],
  "code_challenge_methods_supported": ["S256"]
}

Соображения безопасности

PKCE обязателенcode_challenge_method=S256 требуется; plain не принимается.

  • Точное совпадение redirect URI — redirect URIs проверяются точно против зарегистрированных значений (без prefix match)
  • Auth коды одноразовые — auth код может быть обменян только один раз; вторая попытка не удаёт
  • Refresh-токен ротация — каждый refresh инвалидирует предыдущий refresh токен чтобы обнаружить и ответить на утечки
  • Short-lived access токены — access токены expiration через 15 минут; клиенты должны refresh для обновления
  • Безопасное хранилище токена — токены захешированы в rest (такой же KDF как personal access токены); plaintext токены никогда не сохраняются

Отзыв доступа

Отзовите токен (access или refresh) в любое время:

POST /oauth/revoke
Content-Type: application/x-www-form-urlencoded

token=<access_or_refresh_token>&
client_id=<id>

Отзыв refresh токена каскадирует: все access токены выданные из этого refresh также инвалидируются.

Интеграция с MCP

Внешние MCP серверы используют OAuth токены чтобы вызывать инструменты AACWorkflow. Токены передаются в Authorization header:

GET /api/issues
Authorization: Bearer <access_token>

Сервер валидирует подпись токена, проверяет expiration и применяет scopes. Если инструмент требует issues:write но токен имеет только issues:read, вызов отрицается с 403 Forbidden.

Лог аудита

Каждое OAuth событие (логин, выдача токена, refresh, отзыв, обнаружение переиспользования) записывается в лог аудита для соответствия и расследования.