Bearer Token
Bearer Token
Bearer Token — это способ доказать серверу право доступа одной строкой в HTTP-заголовке
Authorization: Bearer <token>. Кто предъявил токен — тот и авторизован, без пароля и без подписи.
История
Слово «bearer» пришло из финансов. Bearer bond — облигация на предъявителя: нет имени владельца, кто держит бумагу — тот и получает выплаты. То же с bearer cheque (чек на предъявителя): не спрашивают паспорт, показал — получил. Эта модель — «владение = право» — и легла в название токена.
В веб-протоколах Bearer Token задокументирован в RFC 6750 («The OAuth 2.0 Authorization Framework: Bearer Token Usage»), опубликован в октябре 2012 года. Авторы — Майкл Джонс (Microsoft) и Дик Хардт (Salesforce, до этого Amazon). RFC 6750 — младший брат RFC 6749 (сам OAuth 2.0), они вышли одним пакетом.
До OAuth 2.0 существовал OAuth 1.0a (RFC 5849, апрель 2010). Он требовал подписывать каждый запрос криптографической подписью HMAC-SHA1 с использованием client_secret. Разработчики жаловались: реализовать правильно было сложно, любая ошибка в канонизации параметров ломала подпись. Проект OAuth 2.0 упростил радикально — «пусть будет строка, отправляй её в заголовке, а безопасность обеспечит TLS». Так появился Bearer.
Дальнейшие вехи:
- 2012 — RFC 6749/6750, «эра Bearer + JWT» начинается.
- 2015 — JWT формализован в RFC 7519. Bearer стал стандартной обёрткой для JWT.
- 2018 — RFC 8705: mTLS-bound tokens (привязка токена к клиентскому TLS-сертификату).
- 2023 — RFC 9449: DPoP (Demonstrating Proof-of-Possession). Возвращает подпись к каждому запросу — попытка вернуть безопасность OAuth 1.0, оставив простоту 2.0.
История, если коротко: маятник качнулся от «сложной подписи каждого запроса» к «простой строке», а потом обратно, потому что перехват Bearer оказался слишком лёгкой атакой.
Что это такое
Bearer Token — это транспортный формат, а не тип секрета. Он говорит только одно: «я даю тебе строку, ты её проверяешь». Что внутри строки — дело сервера:
- Может быть opaque token: случайная строка (например,
ghp_xn8Jk...), которую сервер сверяет с базой сессий. - Может быть JWT: самодостаточный подписанный JSON, где сервер по подписи проверяет валидность без обращения к БД.
- Может быть даже UUID или строка вида
sk-proj-abc123...(как API-ключи OpenAI/Anthropic).
Синтаксис заголовка описан в RFC 6750:
Authorization: Bearer <token>
Слово Bearer фиксировано, регистр не важен (bearer, BEARER работают, но канон — Bearer). После пробела идёт токен из ограниченного набора символов (A-Z a-z 0-9 - . _ ~ + / и = в конце). Это подмножество Base64URL — сделано специально, чтобы токен можно было положить куда угодно без экранирования.
Чем Bearer отличается от Basic (Authorization: Basic <base64>): Basic передаёт логин:пароль в кодировке Base64 (не шифровании). Bearer передаёт токен без имени пользователя — сервер сам понимает, кому он выдан. Basic ассоциируется с одним пользователем на всю жизнь пароля, Bearer — с одной сессией на короткий срок.
Чем Bearer отличается от API Key (кастомные заголовки X-API-Key: ...): фактически ничем принципиально — оба «строка в заголовке = доступ». Но Bearer стандартизирован, а API Key каждый сервис реализует по-своему. Многие API (Stripe, GitHub) исторически начали с API Key и постепенно переходят на Bearer.
Чем Bearer отличается от Cookie: cookie автоматически прикрепляется браузером ко всем запросам к домену. Bearer нужно явно добавить в код (в fetch/axios/curl). Cookie удобны для веб-приложений, Bearer — для API-клиентов и SPA.
Аналогии из жизни
Билет в кино. Кассир не спрашивает паспорт: показал корешок — прошёл. Кто передаст билет другу — тот и посмотрит фильм.
Где ломается: билет обычно одноразовый и на конкретный сеанс. Bearer же можно использовать сотни раз в течение TTL. Более честная аналогия — абонемент в спортзал по QR-коду: приложил телефон, повернул турникет.
Ключ от гостиничного номера. Магнитная карта не привязана к твоему лицу — приложил, дверь открылась. Кому передашь — тот и войдёт. TTL: до конца бронирования.
Где ломается: гостиничный ключ работает только с конкретной дверью. Bearer часто работает со всеми ресурсами API, к которым выдан scope — украл один токен, получил всё, что мог делать владелец.
Купон на предъявителя. «Первому пришедшему — скидка 20%». Купон не именной, кто первый — того и купон.
Где ломается: купон одноразовый. Bearer же остаётся валидным до истечения — украдешь и будешь использовать месяц, пока владелец не заметит.
Общий смысл всех аналогий: владение = право. Токен не знает, кто ты, он знает только, что кто-то однажды его получил в обмен на пароль/логин, и до конца TTL этот «кто-то» считается уполномоченным.
Как это работает
Жизненный цикл Bearer Token в типичном OAuth-приложении:
1. Аутентификация. Пользователь заходит на страницу авторизации сервиса (условно login.example.com), вводит логин и пароль. Форма отправляет данные на сервер.
2. Выдача токена. Сервер проверяет пароль. Если всё ок, генерирует токен (случайную строку или подписанный JWT) и возвращает в HTTP-ответе:
HTTP/1.1 200 OK
Content-Type: application/json
{
"access_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
"token_type": "Bearer",
"expires_in": 3600,
"refresh_token": "def502004a..."
}
Поле token_type: Bearer — прямое указание клиенту, что токен нужно посылать в заголовке Authorization: Bearer ....
3. Использование. Клиент (мобильное приложение, SPA, скрипт) сохраняет токен и добавляет его к каждому запросу к API:
GET /api/v1/reports HTTP/1.1
Host: api.example.com
Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...
4. Проверка на сервере. Сервер получает запрос, парсит заголовок, извлекает токен. Дальше — два сценария:
- Opaque token: сервер идёт в БД/Redis и ищет запись с этим токеном. Если нашёл и не истёк — авторизует.
- JWT: сервер проверяет подпись публичным ключом. Если валидна и exp в будущем — авторизует, ничего не спрашивая у БД.
5. Ответ. Если токен валиден — 200 с данными. Если нет — 401 с заголовком:
HTTP/1.1 401 Unauthorized
WWW-Authenticate: Bearer realm="api", error="invalid_token", error_description="token expired"
6. Refresh. Когда access_token истёк, клиент шлёт refresh_token на специальный эндпоинт (/oauth/token с grant_type=refresh_token) и получает свежий access_token. Refresh_token живёт дольше (недели/месяцы) и хранится в более безопасном месте.
Три способа положить токен в запрос (RFC 6750 §2):
- HTTP-заголовок (рекомендуется):
Authorization: Bearer <token>. Самый безопасный — не попадает в логи, не сохраняется в истории браузера. - Form body (только для
application/x-www-form-urlencodedPOST):access_token=xxxв теле. Редкий вариант. - URI query (не рекомендуется):
?access_token=xxx. Работает, но токен попадает в логи веб-сервера, Referer, историю браузера. Использовать только если нельзя иначе.
Обязательный TLS. Bearer передаётся в открытом виде. Без HTTPS любой сниффер на пути (публичный Wi-Fi, скомпрометированный роутер) читает токен как есть. Именно поэтому RFC 6750 §5.3 буквально требует HTTPS — и все крупные API его требуют.
Где встречается в обычной жизни
- Ты залогинился в приложение банка на телефоне. Приложение получило Bearer Token, теперь при каждом открытии кнопка «баланс» дёргает API банка с этим токеном. Через 15 минут неактивности токен протухает, приложение шлёт refresh — незаметно для тебя.
- Ты нажал «Войти через Google» на стороннем сайте. Google вернул сайту Bearer Token с ограниченным scope (например, «читать email»). Сайт использует его, чтобы получить твой email и создать аккаунт.
- Открыл ноутбук после сна — Slack показывает «reconnecting». Токен ещё живой, приложение переподключается по WebSocket с Bearer.
- Курьер пришёл с промокодом-QR-ссылкой из СМС. Внутри ссылки — токен, который открывает форму с уже подтянутым заказом.
- Умная колонка отвечает на «включи Spotify». Колонка держит долгоживущий Bearer от твоего Spotify-аккаунта.
Во всех этих случаях ты не видишь ни одной строки — просто «работает». Внутри же всегда один и тот же заголовок.
Где встречается в IT и бизнесе
- REST API любого крупного сервиса. GitHub API (
Authorization: Bearer ghp_...), Stripe (sk_live_...), OpenAI (sk-proj-...), Anthropic (sk-ant-...), Slack (xoxb-...), Notion, Airtable, Yandex.Metrika API — все Bearer. - Внутренние микросервисы. Один сервис ходит в другой с Bearer, выданным центральным Identity Provider (Keycloak, Auth0, Okta).
- SPA + backend. Vue/React приложение получает Bearer от backend, дальше все fetch к API идут с этим заголовком.
- CI/CD. GitHub Actions хранит
GITHUB_TOKEN,PAT(Personal Access Token) — тот же Bearer, только с расширенным TTL. - Мобильные приложения. iOS/Android клиенты используют Bearer через
Authorizationheader в URLSession/OkHttp.
Классы задач, где Bearer — правильный выбор:
- API, к которому обращаются программные клиенты (не браузер с формой логина).
- Stateless-серверы, где не хочется хранить сессии в общей БД (JWT + Bearer).
- Микросервисная архитектура, где сессия должна путешествовать между сервисами.
- Публичные API с ротацией ключей.
Кто пользуется
- GitHub — миллиарды API-запросов в день с Bearer-токенами. Персональные токены и OAuth-приложения.
- Google Cloud, AWS, Azure — во внутренних SDK часто оборачивают в Bearer поверх собственных схем.
- Stripe — весь платёжный API работает через Bearer (
Authorization: Bearer sk_...). - OpenAI, Anthropic — LLM API. Каждая генерация — POST с Bearer.
- Slack, Discord, Telegram Bot API — боты держат постоянный Bearer.
- Auth0, Okta, Keycloak, AWS Cognito — платформы, чья основная работа — выдавать и валидировать Bearer.
- Всё, что реализует OAuth 2.0 — а это де-факто стандарт для «войти через X»: Google, Apple, Meta, Yandex, VK, GitHub, Microsoft.
Масштаб: только GitHub API отдаёт больше 10 миллиардов запросов в день, каждый с Bearer в заголовке. У Stripe — миллиарды платёжных операций в год, все через Bearer.
Альтернативы и конкуренты
Basic Auth (RFC 7617)
+ Простой как валенок: Authorization: Basic base64(login:password).
− Пароль передаётся при каждом запросе (в base64, что не шифрование). Утёк один запрос — утёк пароль навсегда.
Digest Auth (RFC 7616)
+ Challenge-response, пароль не передаётся напрямую.
− Сложный, устарел, редко используется. Не решает проблему MITM без TLS.
API Key в кастомном заголовке (X-API-Key: xxx)
+ Простой, привычный для многих сервисов.
− Не стандартизирован, каждый API — своя реализация. По сути тот же Bearer, но без RFC.
OAuth 1.0 (HMAC-подпись)
+ Не боится перехвата: подпись включает URL, тело, timestamp, nonce.
− Очень сложная реализация. Каждый запрос требует канонизации — источник багов.
AWS Signature Version 4 (HMAC)
+ Каждый запрос подписан, timestamp защищает от replay.
− Сложная реализация, специфичен для AWS.
mTLS (Mutual TLS)
+ Клиент имеет сертификат, аутентификация на уровне TLS-хендшейка. Токен не нужен вообще.
− Требует управления клиентскими сертификатами. Сложно для мобильных/веб-клиентов.
DPoP (RFC 9449)
+ Bearer + JWS-подпись каждого запроса. Кража токена бесполезна без ключа.
− Новый, поддержка вне OAuth-провайдеров пока слабая.
Cookie + CSRF Token
+ Автоматически прикрепляется к запросам, httpOnly защищает от XSS.
− Работает только в браузере. CSRF-токен добавляет сложности. Ровно этот сценарий Паша встретил вчера с Laravel/Смартисом — там был не Bearer, а именно cookie + XSRF-token, потому и подделка запроса не проходила.
Когда НЕ стоит использовать
- Когда нет TLS. Bearer в открытом канале — приглашение к краже. Если по каким-то причинам HTTPS невозможен (легаси-протокол, internal cleartext), выбирай HMAC-подпись или mTLS.
- Когда нужна non-repudiation (клиент потом не должен иметь возможность отказаться от факта запроса — например, платёжные операции с юридическими последствиями). Bearer не даёт доказательства, что запрос сделал именно владелец токена. Нужна подпись.
- Когда клиент недоверенный и токен долгоживущий. Мобильные приложения, где токен может утечь через reverse engineering. Здесь спасают короткий TTL + refresh с ротацией, PKCE, DPoP.
- Для передачи через URL (например, ссылки в письмах). Токен попадёт в логи, историю браузера, Referer. Используй одноразовые signed URL с ограниченным TTL и scope.
- Для sensitive UI-действий в браузере, если ты хранишь Bearer в LocalStorage — любая XSS-уязвимость сливает токен. httpOnly cookie для этого сценария надёжнее.
Связанные понятия
- OAuth 2.0 — фреймворк авторизации, определяющий, как клиент получает access_token; Bearer — один из транспортных форматов этого токена.
- JWT (JSON Web Token) — самодостаточный формат подписанного токена; часто именно он лежит внутри Bearer.
- Access Token vs Refresh Token — короткоживущий Bearer для API-вызовов и долгоживущий токен для обновления первого.
- PKCE (Proof Key for Code Exchange) — расширение OAuth для мобильных/SPA, защищает обмен кода на токен от перехвата.
- DPoP — привязка Bearer к криптографическому ключу клиента, борется с кражей токена.
- Scope — набор разрешений, зашитый в токен: что именно им можно делать.
- CSRF (Cross-Site Request Forgery) — атака на cookie-based auth, которая для Bearer не работает (заголовок Authorization не отправляется автоматически cross-origin).
Литература и источники
- RFC 6750 — «The OAuth 2.0 Authorization Framework: Bearer Token Usage», М. Джонс и Д. Хардт, 2012. Первоисточник. Читать на datatracker.ietf.org.
- RFC 6749 — «The OAuth 2.0 Authorization Framework», 2012. Родительская спецификация.
- RFC 9449 — «OAuth 2.0 Demonstrating Proof-of-Possession at the Application Layer (DPoP)», 2023. Свежий взгляд, как чинить проблемы Bearer.
- «OAuth 2 in Action», Джастин Ричер и Антонио Санзо, 2017 (en). Лучшая книга-обзор, с примерами кода.
- Wikipedia: OAuth — обзорная статья, en.wikipedia.org/wiki/OAuth. Хороший старт.
- auth0.com/docs — документация Auth0, много практических гайдов по Bearer, JWT, refresh-flow.
- Видео: искать в YouTube по запросу «OAuth 2.0 explained» — канал OktaDev даёт крепкое базовое видео на 20 минут.
Где встретилось у меня
Вчера в проекте по вытягиванию аналитики из Смартиса ты через Playwright пытался обойти публичный Bearer-API, который «тихо не отдавал показы». Пришлось логиниться в UI, ловить заголовки реального XHR-запроса и повторять их. Отдельный сюжет — понимание, что там не Bearer, а сессионная кука Laravel с CSRF-токеном, поэтому подделка через fetch не проходила. Ровно классическая развилка «Bearer vs Cookie + CSRF».
Краткое резюме
- Bearer Token — способ авторизации в API: одна строка в заголовке
Authorization: Bearer <token>, кто владеет — тот и авторизован. - Название — из финансов (bearer bond, чек на предъявителя). Формализован в RFC 6750 (2012) вместе с OAuth 2.0.
- Токен внутри может быть чем угодно: opaque UUID, JWT, API-ключ. Bearer определяет только транспорт.
- Обязателен HTTPS: перехват = кража ключа. Не класть в URL, короткий TTL, refresh для обновления.
- Альтернативы: Basic (устарел), API Key (нестандартизированный Bearer), OAuth 1.0 HMAC (сложно, но безопаснее), mTLS, DPoP, Cookie+CSRF.
- Не использовать: без TLS, для non-repudiation операций, для передачи через URL, для долгоживущих секретов в недоверенных клиентах.