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 может любой. Это не шифрование, а кодировка. Поэтому в нём не хранят секретов, а по полю
expможно сразу понять, не истёк ли токен. - Живой токен не вставляют в онлайн-декодеры. Это действующий ключ доступа, и сайт, куда вы его вставили, может им воспользоваться. Для разбора берите токен с тестового стенда или уже истёкший.
Bearer, Basic и API-ключ: в чём разница#
| Bearer | Basic | API-ключ | |
|---|---|---|---|
| Как выглядит | 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: вы вставляете токен, а клиент сам собирает заголовок.
В 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", или прямо в теле. Если там пусто, пройдитесь по списку:
- Нет слова
Bearerили после него нет пробела. Тестовый API на такой запрос отвечаетexpected Authorization: Bearer <token>. Bearerдва раза. Токен вставили вместе со словомBearerв поле, которое добавляет его само. Так часто бывает в окне Authorize в Swagger UI: при схемеbearerтуда вставляют только токен (о Swagger UI есть отдельная статья).- Лишние символы: кавычки вокруг токена или кусок соседнего текста, скопированный вместе с ним.
- Токен истёк. Проверьте поле
exp, если это JWT, или просто получите новый. - Токен от другого стенда. Токен со стейджа на проде не работает. Если вы держите токены в окружениях, проверьте, какое из них выбрано (об этом есть история про пятницу и прод).
- Заголовок потерялся по дороге. Например, после перенаправления на другой адрес: 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-токен в чате, на скриншоте или в истории терминала сработает у любого, кто его увидел. Если такой токен уже ушёл, в статье про токен на скриншоте по шагам расписано, что делать.