Перейти к содержимому
LegalStack
Основы API

Аутентификация

OAuth 2.0, привязка токена к клиенту по DPoP или mTLS, серверный nonce, scopes.

OAuth 2.0

API LegalStack использует OAuth 2.0 с требованиями OAuth 2.1: PKCE обязателен, токены короткоживущие, каждый access token привязан к клиенту. Точка выдачи токенов — POST https://api.legalstack.ru/oauth/token, метаданные — https://api.legalstack.ru/.well-known/oauth-authorization-server.

Поддерживаемые сценарии получения токена:

  • Client Credentials — для серверных интеграций от имени команды.
  • Authorization Code с PKCE — для приложений, действующих от имени пользователя.

Все операции OAuth (авторизация, обмен кода, обновление, отзыв и проверка токена) — в разделе «OAuth» справочника API.

Привязка токена к клиенту

Платформа не выдаёт токенов, которыми может воспользоваться любой, кто их перехватил. Каждый access token привязан к клиенту одним из двух способов, и ресурсные сервисы отклоняют токен без привязки:

  • DPoP (RFC 9449) — токен привязан к ключу, который клиент сгенерировал сам и хранит у себя. Это основной способ для интеграций, SDK и MCP-клиентов. В справочнике API схема безопасности называется <Fact k="dpopSecurityScheme" />.
  • mTLS (RFC 8705) — токен привязан к клиентскому сертификату, которым установлено TLS-соединение. Так работают сервисы самой платформы и клиенты, которым платформа выдала сертификат. Схема безопасности — <Fact k="mtlsSecurityScheme" />.

Как работает DPoP

  1. Клиент один раз создаёт пару ключей. Поддерживаемые алгоритмы: ES256, ES384, ES512, EdDSA, PS256, PS384, PS512, RS256. Приватный ключ не покидает клиента.
  2. На каждый HTTP-запрос клиент подписывает этим ключом короткий JWT-доказательство и передаёт его в заголовке DPoP. В доказательстве: htm (метод), htu (URL без query и fragment), iat, уникальный jti, nonce сервера, а для запросов с токеном ещё ath — SHA-256 от access token в base64url. В заголовке JWT: typ: dpop+jwt, alg и публичный ключ в jwk.
  3. Токен передаётся со схемой DPoP, не Bearer:
Запрос
GET /api/v1/tasks HTTP/1.1
Authorization: DPoP <access_token>
DPoP: <доказательство для GET https://api.legalstack.ru/api/v1/tasks>
  1. Сервер проверяет подпись, совпадение ключа с привязкой в токене (cnf.jkt), метод, адрес, свежесть, ath, nonce и однократность jti. Доказательство действительно 300 секунд с момента iat, повторное использование jti отклоняется.

Серверный nonce

Чтобы доказательства нельзя было заготовить впрок, сервер требует включать в них свой nonce и присылает актуальное значение в заголовке DPoP-Nonce каждого ответа. Значение действует не меньше 120 секунд с момента выдачи, поэтому для следующего запроса берите nonce из последнего ответа.

Если клиент только запускается или простаивал дольше этого срока, получите nonce заранее: GET на путь /.well-known/dpop-nonce того же хоста API отвечает 204 без тела и с заголовком DPoP-Nonce. Токен и доказательство для этого запроса не нужны. Параллельные запросы после простоя дождитесь одного такого запроса, тогда все они уйдут с действующим nonce.

Запрос без nonce или с устаревшим значением не выполняется:

  • точка выдачи токенов отвечает 400 с error: use_dpop_nonce;
  • ресурсные сервисы отвечают 401 с кодом USE_DPOP_NONCE и заголовком WWW-Authenticate: DPoP error="use_dpop_nonce".

В обоих случаях в ответе есть DPoP-Nonce: повторите тот же запрос с новым доказательством, включив это значение в nonce.

Получение токена

На POST /oauth/token клиент передаёт заголовок DPoP с доказательством для этого запроса. В ответе token_type равен DPoP, а токен содержит отпечаток ключа в cnf.jkt. Запрос за токеном без доказательства и без клиентского сертификата отклоняется с error: invalid_dpop_proof.

Ответ
HTTP/1.1 200 OK
DPoP-Nonce: <nonce для следующего доказательства>
Content-Type: application/json

{ "access_token": "…", "token_type": "DPoP", "expires_in": 900, "scope": "tasks:read" }

Токены короткоживущие; обновляйте их по refresh_token или повторным client-credentials запросом тем же ключом DPoP. Ответ 401 с кодом TOKEN_EXPIRED — сигнал получить новый токен. Refresh token выдаётся только клиентам с DPoP и клиентам с сертификатом, при каждом обновлении он ротируется.

Ресурсы

Каждый токен выдаётся для одного ресурса платформы, и ресурс указывается параметром resource (RFC 8707) при авторизации и при запросе токена:

РесурсДля чегоScope
https://api.legalstack.ruREST API, ресурс по умолчаниювсе scope каталога, кроме mcp:tools:execute
https://mcp.legalstack.ru/mcpMCP-сервер, все разделыmcp:tools:execute
https://mcp.legalstack.ru/mcp/<раздел>MCP-сервер, один разделmcp:tools:execute

Запрос токена для любого другого адреса отклоняется с error: invalid_target. В настройках OAuth-приложения можно сузить список ресурсов, для которых приложение получает токены: пустой список разрешает все ресурсы платформы.

Персональные ключи

Персональный ключ создаётся в «Настройки → API → API-ключи» и начинается с lk_. Это долгоживущий секрет пользователя, и в запросах к API он не передаётся: ресурсные сервисы отвечают 401 с кодом INVALID_TOKEN на любой запрос с ключом в заголовке Authorization. Ключ обменивается на короткоживущий токен доступа по RFC 8693, а токен привязывается к ключу DPoP так же, как в разделе выше.

Обмен ключа
POST /oauth/token HTTP/1.1
Host: api.legalstack.ru
Content-Type: application/x-www-form-urlencoded
DPoP: <доказательство для POST https://api.legalstack.ru/oauth/token>

grant_type=urn:ietf:params:oauth:grant-type:token-exchange
&subject_token=lk_…
&subject_token_type=urn:legalstack:params:oauth:token-type:personal-token
&resource=https://api.legalstack.ru
&scope=tasks:read
Ответ
{
  "access_token": "…",
  "issued_token_type": "urn:ietf:params:oauth:token-type:access_token",
  "token_type": "DPoP",
  "expires_in": 900,
  "scope": "tasks:read"
}
  • Без DPoP ключ не обменивается. Запрос без доказательства получает error: invalid_dpop_proof, первый запрос с доказательством без nonce получает use_dpop_nonce и значение в заголовке DPoP-Nonce.
  • Scope токена не шире ключа и ресурса. Без параметра scope токен получает все scope ключа, доступные для ресурса. Ключ без ограничений получает все scope ресурса. Запрос scope, которого нет у ключа или у ресурса, отклоняется с error: invalid_scope.
  • Токен не переживает ключ. Срок токена не больше срока ключа, а отзыв ключа сразу делает недействительными все выданные по нему токены.
  • Ключ не управляет учётными данными. Создавать и отзывать ключи и OAuth-приложения можно только из пользовательской сессии в веб-приложении.

Scopes

Доступ контролируется scopes вида <домен>:<действие> — например tasks:read, registry:write, webhooks:write. Требуемые scopes каждой операции указаны в справочнике API, полный список — в каталоге scope. Запрашивайте минимально необходимый набор: запрос с недостающим scope получит 403 с кодом OAUTH_INSUFFICIENT_SCOPE.

Ключи подписи

Публичные ключи для проверки JWT публикуются в JWKS: https://api.legalstack.ru/.well-known/jwks.json. Ключи ротируются — резолвьте их по kid из заголовка токена, а не кэшируйте единственный ключ навсегда.

На этой странице