← Блог

Bearer-токен: что это и как передать его в запросе

Коротко: Bearer-токеном называют строку доступа, которую выдаёт сервер: после входа по логину и паролю, через OAuth 2.0 или в настройках сервиса. Клиент прикладывает её к каждому запросу в заголовке Authorization, после слова Bearer и одного пробела:

Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...

Слово bearer значит «предъявитель». Сервер пускает любого, кто принёс токен, и не выясняет, кто именно его принёс. Как с билетом в кино: на входе смотрят билет, а не паспорт. Поэтому Bearer-токен берегут как пароль.

Схему описывает стандарт RFC 6750, часть OAuth 2.0, но пользуются ей далеко не только в OAuth.

Как передать Bearer-токен в заголовке Authorization#

Заголовок состоит из трёх частей: имя Authorization, слово Bearer, один пробел и сам токен. Больше ничего: ни кавычек, ни двоеточия после Bearer.

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

Регистр слова Bearer по стандарту не важен, bearer тоже сработает. Но некоторые серверы проверяют его буквально, так что надёжнее писать с заглавной буквы.

В curl это выглядит так (подробнее о флагах в статье про curl):

curl https://playground.tetiva.app/bearer \
  -H "Authorization: Bearer abc123"

Адрес ведёт на наш тестовый API. Он принимает любой токен и показывает, что получил.

В коде заголовок задают так же, как любой другой. На JavaScript:

fetch("https://playground.tetiva.app/bearer", {
  headers: { Authorization: `Bearer ${token}` },
});

С axios:

axios.get("https://playground.tetiva.app/bearer", {
  headers: { Authorization: `Bearer ${token}` },
});

На Python с библиотекой requests:

requests.get("https://playground.tetiva.app/bearer",
             headers={"Authorization": f"Bearer {token}"})

Где взять Bearer-токен#

Токен выдаёт сервер, и способ зависит от сервиса. Чаще всего встречаются три:

  • Вход по логину и паролю. Отправляете их на адрес вроде /auth/login, в ответе приходит access_token. Дальше он идёт в каждый запрос.
  • OAuth 2.0. Приложение получает токен у сервера авторизации, например после кнопки «Войти через…» или по паре client ID и client secret, если запросы делает сервис, а не человек.
  • Личный токен из настроек. Многие сервисы, например GitHub и GitLab, дают выпустить токен в личном кабинете. Он живёт долго, и его можно отозвать.

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

В ответе сервера это обычно выглядит так:

{
  "access_token": "eyJhbGciOi...",
  "token_type": "Bearer",
  "expires_in": 3600,
  "refresh_token": "8xLOxBtZp8..."
}

Поле token_type и говорит, что токен предъявляют по схеме Bearer. Поэтому access token так часто и называют Bearer-токеном.

Чем Bearer отличается от JWT#

Bearer означает способ передать токен, а JWT задаёт формат самого токена. Их часто путают, потому что JWT чаще всего передают именно как Bearer. Но Bearer-токен может быть и просто случайной строкой.

Непрозрачный токен выглядит как 9f2c4e7a1b.... Из него ничего не узнать, а сервер проверяет его по своей базе.

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

JWT читается без ключа: подпись защищает токен от подделки, но не скрывает содержимое
  • «Расшифровать» JWT может любой. Это не шифрование, а кодировка. Поэтому в нём не хранят секретов, а по полю exp можно сразу понять, не истёк ли токен.
  • Живой токен не вставляют в онлайн-декодеры. Это действующий ключ доступа, и сайт, куда вы его вставили, может им воспользоваться. Для разбора берите токен с тестового стенда или уже истёкший.

Bearer, Basic и API-ключ: в чём разница#

BearerBasicAPI-ключ
Как выглядитAuthorization: Bearer <токен>Authorization: Basic <логин:пароль в Base64>Свой заголовок, например X-Api-Key: <ключ>, или параметр в адресе
Что внутриТокен, выданный серверомЛогин и пароль, просто закодированныеПостоянный ключ
Срок жизниОбычно короткийПока не сменят парольПока не отзовут
Где встречаетсяБольшинство современных API, OAuth 2.0Внутренние сервисы, старые APIПубличные API, запросы между сервисами

Сам по себе ни один из трёх способов запрос не шифрует, это делает HTTPS. Поэтому токены отправляют только по https://.

Стандарт разрешает передать токен и параметром access_token в адресе, но советует так не делать: адрес оседает в логах серверов и в истории браузера. Есть и DPoP (RFC 9449): он привязывает токен к ключу, который есть только у клиента, так что одного украденного токена мало. Большинство API пока обходятся обычным Bearer.

Bearer-токен в Postman и других API-клиентах#

Вписывать заголовок Authorization руками необязательно. В Postman, Insomnia, Tetiva и других клиентах на вкладке Auth есть тип Bearer Token: вы вставляете токен, а клиент сам собирает заголовок.

Вкладка Auth в Tetiva: префикс Bearer по умолчанию, токен взят из переменной окружения

В Tetiva у этого типа два поля, Prefix и Token. Префикс по умолчанию Bearer, но некоторые API ждут другое слово, например Token, и его можно заменить, а MAX Bot API ждёт токен вообще без префикса. Если поле токена пустое, заголовок не отправляется вовсе. Перевод строки в конце вставленного токена отрезается сам, так что токен можно спокойно копировать из терминала.

Сам токен лучше держать в переменной окружения {{token}}: когда он сменится, править придётся одно место, а для стенда и прода можно завести разные значения. Если токен у всей коллекции один, задайте авторизацию на самой коллекции, и запросы с типом Inherit подхватят её сами. Подробности в документации по авторизации.

Если токен приходит в ответ на логин, его можно сохранять в переменную скриптом после ответа:

pm.environment.set("token", pm.response.json().access_token);

Если токен выдаёт OAuth 2.0, скрипт не нужен: выберите в Tetiva тип OAuth 2.0 и нажмите Get token. Когда срок токена подходит к концу, клиент сам обновит его по refresh-токену перед отправкой запроса (подробнее).

Почему 401, хотя токен передан#

Сначала посмотрите на ответ: многие серверы пишут причину в заголовке WWW-Authenticate, например error="invalid_token", или прямо в теле. Если там пусто, пройдитесь по списку:

  1. Нет слова Bearer или после него нет пробела. Тестовый API на такой запрос отвечает expected Authorization: Bearer <token>.
  2. Bearer два раза. Токен вставили вместе со словом Bearer в поле, которое добавляет его само. Так часто бывает в окне Authorize в Swagger UI: при схеме bearer туда вставляют только токен (о Swagger UI есть отдельная статья).
  3. Лишние символы: кавычки вокруг токена или кусок соседнего текста, скопированный вместе с ним.
  4. Токен истёк. Проверьте поле exp, если это JWT, или просто получите новый.
  5. Токен от другого стенда. Токен со стейджа на проде не работает. Если вы держите токены в окружениях, проверьте, какое из них выбрано (об этом есть история про пятницу и прод).
  6. Заголовок потерялся по дороге. Например, после перенаправления на другой адрес: curl с -L не отправит Authorization на другой хост, если не добавить --location-trusted.

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

Проверьте на тестовом API#

Отправьте запрос без заголовка, без слова Bearer и с правильным заголовком:

# 401: заголовка нет
curl https://playground.tetiva.app/bearer

# 401: токен без слова Bearer
curl https://playground.tetiva.app/bearer -H "Authorization: abc123"

# 200: всё правильно
curl https://playground.tetiva.app/bearer -H "Authorization: Bearer abc123"

Bearer-токен в чате, на скриншоте или в истории терминала сработает у любого, кто его увидел. Если такой токен уже ушёл, в статье про токен на скриншоте по шагам расписано, что делать.