# Аутентификация API и подпись запросов: токены, HMAC, OAuth, mTLS

> HTTP API аутентифицируют вызывающих учётными данными в заголовке Authorization — API-ключом или bearer token (Authorization: Bearer <token>). Более сильные схемы подписывают каждый запрос через HMAC над каноническим запросом, чтобы учётные данные никогда не были воспроизводимыми, используют OAuth 2.0 client-credentials для токенов machine-to-machine и добавляют взаимный TLS там, где нужна идентичность на транспортном уровне.

- Канонический URL: https://www.broadnet.me/ru/reference/api-authentication-and-signing
- Язык: ru
- Последнее обновление: 2026-07-19
- Издатель: BroadNet (https://www.broadnet.me)

Стандартные способы аутентификации HTTP API сообщений: bearer token и API-ключи в заголовке Authorization, подпись запросов через HMAC над каноническим запросом, ограничение области и ротация ключей, взаимный TLS и OAuth 2.0 client-credentials для доступа machine-to-machine.

## Bearer token и API-ключи

Простейшая аутентификация — учётные данные bearer: клиент предъявляет секретный токен в заголовке Authorization, а сервер его проверяет. RFC 9110 определяет заголовок Authorization и префикс его схемы, а OAuth 2.0 определяет схему Bearer — Authorization: Bearer <token> — определяющее свойство которой в том, что доступ даёт само обладание, поэтому токен должен ходить только поверх TLS и никогда не появляться в URL, журнале или сообщении об ошибке. API-ключ — та же идея с более долгоживущим, часто бессрочным секретом. Поскольку учётные данные bearer воспроизводимы при захвате, это базовый уровень, а не потолок: их легко интегрировать, и поверх TLS они вполне достаточны для большей части трафика, но операции высокой ценности часто накладывают сверху подпись запросов.

*Bearer token в запросе*

```http
POST /v1/messages HTTP/1.1
Host: api.example
Authorization: Bearer eyJhbGciOi...  # secret; TLS only, never logged
Content-Type: application/json
```

## Подпись запросов через HMAC

Подпись запросов поднимает планку: вместо отправки секрета клиент использует его для вычисления HMAC над каноническим представлением запроса и отправляет только подпись. Сервер, держа тот же секрет, заново вычисляет подпись и сравнивает. Поскольку подпись покрывает метод, путь, ключевые заголовки и хеш тела, захваченную подпись нельзя воспроизвести против другого запроса, а поскольку сам секрет никогда не покидает клиента, захват одного запроса не раскрывает учётные данные. Конструкция зеркалит подпись webhook в обратном направлении и использует тот же примитив HMAC-SHA256 (RFC 2104 / RFC 6234). Тонкая часть — канонический запрос: обе стороны должны согласиться байт в байт о том, как его сериализовать, иначе каждая подпись не совпадёт.

*Канонический запрос и подпись*

```text
canonical =
  HTTP-METHOD  + '\n' +
  URI-PATH     + '\n' +
  SORTED-QUERY + '\n' +
  SIGNED-HEADERS (name:value, sorted, '\n'-joined) + '\n' +
  HEX(SHA256(raw_body))

signature = HMAC_SHA256(secret, canonical)

Authorization: SIGV1 Credential=<key-id>,
  SignedHeaders=host;x-date;content-type, Signature=<hex>
```

## Подписанные заголовки и дата запроса

Две детали делают подпись запросов надёжной. Во-первых, явный список SignedHeaders называет ровно те заголовки, что покрыты, чтобы посредник, добавивший или переупорядочивший несвязанные заголовки, не аннулировал подпись, тогда как любой выбранный клиентом для подписи заголовок защищён от подделки. Во-вторых, дата запроса (подписанный X-Date или стандартный заголовок Date) является частью канонического запроса и сверяется с часами сервера в пределах допуска — та же защита от повторов, что у webhook, применённая к входящим вызовам API. Вместе они означают, что подписанный запрос привязан к своему точному содержимому, объявленным заголовкам и узкому окну времени; захваченный запрос бесполезен через несколько минут.

## Ограничение области и ротация ключей

Учётные данные должны нести наименьшую работающую привилегию и быть ротируемыми без простоя. Ограничение области привязывает разрешения к ключу — какие операции он может вызывать, из какого источника, с какой скоростью, — чтобы ключ, который только отправляет сообщения, не мог читать настройки аккаунта, а радиус поражения утёкшего ключа был ограничен. Ротация следует паттерну перекрывающихся ключей: выдать новые учётные данные, запустить оба параллельно, пока клиенты мигрируют, затем отозвать старые, чтобы ничего не сломалось на лету. Ключи должны быть идентифицируемыми (несекретный key id ходит в запросе, чтобы сервер знал, против какого секрета проверять и какую область применять) и отзываемыми по отдельности, чтобы одна скомпрометированная интеграция была отсечена, не нарушив остальные.

*Сравнение схем аутентификации*

| Схема | Что передаётся | Мощность / использование |
|---|---|---|
| Ключ API | Долгоживущий секрет в Authorization | Простой базовый вариант; только TLS; легко утекает в логи |
| Токен Bearer (OAuth 2.0) | Кратковременный токен доступа | С ограниченным сроком действия и областью; обновляется через token endpoint |
| Подпись запросов HMAC | Подпись (секрет остаётся локально) | Устойчивость к повторному воспроизведению, обнаружение подделки для каждого запроса |
| mTLS | Сертификат клиента X.509 | Идентификация на транспортном уровне; надёжно, но сложнее в эксплуатации |

## Взаимный TLS

Взаимный TLS аутентифицирует клиента на транспортном уровне: вдобавок к серверу, предъявляющему сертификат, клиент предъявляет собственный сертификат X.509 во время рукопожатия, а сервер допускает только соединения, чей сертификат выстраивается в цепочку к доверенному CA и совпадает с зарегистрированной идентичностью. Это привязывает идентичность API к криптографическому ключу, управляемому на уровне соединения, а не к секрету bearer в заголовке, что привлекательно для высоконадёжных связей machine-to-machine и для привязки партнёра к конкретным сертификатам. Цена — операционная: выпуск, распространение, ротация и отзыв сертификатов, — поэтому mTLS обычно резервируют для наиболее чувствительных интеграций, часто в сочетании с bearer token или подписью для тонкой авторизации поверх грубой транспортной идентичности.

## OAuth 2.0 client-credentials для M2M

Для интеграций сервер-сервер без присутствующего конечного пользователя OAuth 2.0 (RFC 6749) определяет грант client-credentials. Клиент аутентифицируется на token endpoint своими client_id и client_secret (или клиентским сертификатом) и получает короткоживущий access token, который затем предъявляет как bearer token в вызовах API, пока тот не истечёт и не будет обновлён. Преимущество перед статическим API-ключом — время жизни и область: токены короткоживущие, поэтому захваченный токен быстро истекает, и они несут явные области, поэтому токен, выпущенный для отправки, нельзя использовать для администрирования аккаунта. Это стандартный паттерн доступа к API machine-to-machine и механизм, который руководство по аутентификации BroadNet конкретно документирует для своих эндпоинтов.

*Запрос токена OAuth 2.0 client-credentials (RFC 6749)*

```http
POST /oauth/token HTTP/1.1
Host: auth.example
Content-Type: application/x-www-form-urlencoded

grant_type=client_credentials
&client_id=<id>
&client_secret=<secret>
&scope=messages:send

-> { "access_token": "...", "token_type": "Bearer",
     "expires_in": 3600, "scope": "messages:send" }
```

## Частые вопросы

### В чём разница между bearer token и подписью HMAC?

Bearer token отправляется в каждом запросе и даёт доступ обладанием, поэтому захваченный токен воспроизводим, пока не истечёт. Подпись HMAC никогда не отправляет секрет — клиент подписывает канонический запрос и отправляет только подпись, поэтому захваченный запрос нельзя воспроизвести против другого вызова, а сами учётные данные никогда не раскрываются.

### Зачем подписи HMAC нужен канонический запрос?

Потому что обе стороны должны вычислить идентичную строку, чтобы получить совпадающие подписи. Канонический запрос точно фиксирует, как сериализуются метод, путь, отсортированный query, подписанные заголовки и хеш тела. Любое расхождение — порядок заголовков, пробелы, повторно закодированное тело — порождает другую подпись, и запрос отклоняется, хотя ничего не подделано.

### Что даёт OAuth 2.0 client-credentials по сравнению с API-ключом?

Короткое время жизни и явную область. Клиент обменивает свои учётные данные на token endpoint на короткоживущий, ограниченный по области access token (RFC 6749). Захваченный токен быстро истекает, а токен, выпущенный для отправки, не может администрировать аккаунт. Статический API-ключ, напротив, долгоживущий и обычно широкий.

### Как ограничивать область и ротировать API-ключи?

Давайте наименьшую привилегию — ограничьте каждый ключ операциями, источниками и скоростью, которые ему нужны, — чтобы утечка была локализована. Ротируйте перекрывающимися ключами: выдайте новые учётные данные, запустите оба параллельно, пока клиенты мигрируют, затем отзовите старые. Ключи должны нести несекретный key id и быть отзываемыми по отдельности, чтобы одна скомпрометированная интеграция была отсечена в одиночку.

### Когда взаимный TLS стоит операционных затрат?

Когда вам нужна криптографическая идентичность на транспортном уровне для высоконадёжной связи machine-to-machine или для привязки партнёра к конкретным сертификатам. mTLS допускает только клиентов, чей сертификат X.509 выстраивается в цепочку к доверенному CA. Его тяжелее эксплуатировать — выпуск, ротация, отзыв, — поэтому его обычно резервируют для наиболее чувствительных интеграций, часто накладывая токен или подпись для авторизации.

### Почему учётные данные bearer никогда не должны попадать в URL или журнал?

Потому что учётные данные bearer дают доступ одним лишь обладанием. URL логируются прокси, хранятся в истории браузера и утекают через заголовок Referer, а журналы приложений широко читаемы, поэтому токен в любом из них фактически раскрыт. Учётные данные bearer должны ходить только в заголовке Authorization поверх TLS и вычищаться из журналов.

## Источники

- [IETF RFC 6749 — The OAuth 2.0 Authorization Framework](https://datatracker.ietf.org/doc/html/rfc6749)
- [IETF RFC 2104 — HMAC: Keyed-Hashing for Message Authentication](https://datatracker.ietf.org/doc/html/rfc2104)

## См. также

- [Проверка подписи webhook](https://www.broadnet.me/ru/reference/webhook-signature-verification)
- [Идемпотентность и ограничение скорости](https://www.broadnet.me/ru/reference/idempotency-and-rate-limiting)
- [Проектирование REST API сообщений](https://www.broadnet.me/ru/reference/rest-messaging-api-design)
- [Ошибки API и пагинация](https://www.broadnet.me/ru/reference/api-errors-and-pagination)
- [Руководство по аутентификации BroadNet](https://www.broadnet.me/ru/developers/authentication)
