Узнайте, что такое JWT (JSON Web Token), как работают его три части, где он используется и ключевые советы по безопасности, чтобы избежать распространённых ошибок с токенами.

JWT (JSON Web Token) — это компактная, URL-безопасная строка, которая представляет набор информации (обычно о пользователе или сессии) и может передаваться между системами. Вы часто увидите её как длинное значение, начинающееся с eyJ..., отправляемое в HTTP-заголовке, например Authorization: Bearer \u003ctoken\u003e.
Традиционные логины часто опираются на серверные сессии: вы входите, сервер сохраняет данные сессии и отдаёт браузеру cookie с ID сессии. Каждый запрос включает эту cookie, и сервер смотрит запись сессии.
С аутентификацией на основе токенов сервер может избежать хранения состояния для каждого запроса пользователя. Клиент держит токен (например, JWT) и прикладывает его к вызовам API. Это популярно для API, потому что:
Важное уточнение: «stateless» не означает «никаких серверных проверок». Многие реальные системы всё ещё дополнительно проверяют токены на предмет статуса пользователя, ротации ключей или механизмов отзыва.
JWT часто несут в себе доказательство аутентификации (вы вошли) и подсказки для авторизации (роли, права, scope), — но сервер всё равно должен применять правила авторизации.
JWT обычно используются как access tokens в:
JWT — компактная строка из трёх частей, каждая base64url-encoded и разделённая точками:
header.payload.signature
Пример (редактировано):
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwiaWF0IjoxNzAwMDAwMDAwfQ.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c…
Header описывает, как был создан токен — главным образом алгоритм подписи (например, HS256, RS256/ES256) и тип токена.
Обычные поля:
typ: часто "JWT" (часто игнорируется на практике)alg: алгоритм подписиkid: идентификатор ключа, помогающий выбрать нужный ключ при ротацииЗаметка по безопасности: не доверяйте header слепо. Применяйте allowlist алгоритмов, которые вы действительно используете, и не принимайте alg: "none".
Payload содержит "claims" — поля о пользователе и контексте токена: для кого он, кто выпустил и когда истекает.
Важно: JWT по умолчанию не шифруются. Base64url делает токен безопасным для URL; он не скрывает данные. Любой, у кого есть токен, может декодировать header и payload.
Поэтому не храните в JWT секреты (пароли, API-ключи) или чувствительные персональные данные.
Подпись создаётся путём подписания header + payload с использованием ключа:
Подпись обеспечивает целостность: сервер убеждается, что токен не был изменён и выпущен доверенным подписантом. Подпись не обеспечивает конфиденциальность.
Поскольку JWT включает header и payload в каждом запросе, где он отправляется, большие токены увеличивают трафик и нагрузку. Держите claims минимальными и предпочитайте идентификаторы вместо громоздких данных.
Claims делятся на две категории: зарегистрированные (стандартизированные имена) и пользовательские (поля вашего приложения).
iss (issuer): кто создал токенsub (subject): о ком токен (часто ID пользователя)aud (audience): для кого предназначен токен (например, конкретное API)exp (expiration time): когда токен должен перестать приниматьсяiat (issued at): когда токен созданnbf (not before): токен не должен приниматься до этого времениВключайте только то, что реально нужно принимающему сервису для принятия решения об авторизации.
Хорошие примеры:
user_id)Избегайте "удобных" claims с копированием профиля: они раздувают токен, быстро устаревают и увеличивают последствия утечки.
Поскольку payload читаем, не храните:
Если нужна чувствительная информация, храните её на сервере и в токен кладите только ссылку (ID), либо используйте зашифрованный формат токена (JWE) при необходимости.
Подпись — это не шифрование.
При выпуске JWT сервер подписывает закодированные header + payload. При предъявлении токена позже сервер пересчитывает подпись и сравнивает. Если кто-то изменит хоть один символ (например, "role":"user" на "role":"admin"), верификация упадёт и токен отвергнут.
JWT — это формат токена. OAuth 2.0 и OpenID Connect (OIDC) — протоколы, описывающие, как приложения запрашивают, выдают и используют токены.
OAuth 2.0 в основном про авторизацию: дать приложению доступ к API от имени пользователя без передачи пароля.
Access-токены обычно короткоживущие (минуты). Короткий срок ограничивает ущерб при утечке.
OIDC добавляет аутентификацию (подтверждение личности) поверх OAuth 2.0 и вводит ID token, который обычно является JWT.
Правило: не используйте ID token для вызова API.
Если нужно больше примеров потоков, см. /blog/jwt-authentication-flow.
Типичный поток выглядит так:
Пользователь входит (email/password, SSO и т.д.). При успехе сервер создаёт JWT (часто это access token) с базовыми claims, такими как subject и expiration.
Сервер подписывает токен и возвращает его клиенту (веб-приложение, мобильное приложение или другой сервис).
Для защищённых эндпоинтов клиент включает JWT в заголовок Authorization:
Authorization: Bearer \u003cJWT\u003e
Перед обслуживанием запроса API обычно проверяет:
exp (не просрочен)iss (ожидаемый issuer)aud (предназначен для этого API)Если все проверки проходят, API считает пользователя аутентифицированным и применяет правила авторизации (например, уровень доступа к записям).
Поскольку часы на системах расходятся, многие системы допускают небольшой clock skew при проверке временных claims, таких как exp и nbf. Держите допуск небольшим, чтобы не увеличивать фактическое время жизни токена больше задуманного.
Выбор места хранения меняет, какие атаки возможны и насколько легко можно повторно использовать токен.
Хранение в памяти (рекомендуется для SPA) — держите access-токен в JS-памяти. Он очищается при перезагрузке и снижает риск «взять позже», но XSS во время выполнения страницы всё ещё может его прочитать. Используйте короткоживущие access-токены и поток обновления.
localStorage/sessionStorage просты, но рискованы: любой XSS может вытянуть токены. Если используете, профилактика XSS обязателна (CSP, экранирование, проверка зависимостей), и держите токены короткоживущими.
Secure cookies (часто самый безопасный выбор для веба) — храните токены в HttpOnly cookie, чтобы JavaScript не мог их прочитать. Минус — риск CSRF, так как браузер автоматически прикладывает cookie.
Если используете cookies, установите:
HttpOnlySecure (только по HTTPS)SameSite=Lax или SameSite=Strict (иногда для кросс-сайтовых потоков нужен SameSite=None; Secure)Также рассмотрите CSRF-токены для запросов, изменяющих состояние.
На iOS/Android храните токены в безопасном хранилище платформы (Keychain / Keystore). Избегайте простых файлов или настроек. Если угроза включает рутованные/джейлбрейкнутые устройства, предполагайте, что извлечение возможно — полагайтесь на короткоживущие токены и серверные механизмы контроля.
Ограничивайте возможности токена: минимальные scope/claims, короткое время жизни access-токенов, и избегайте вложения чувствительных данных.
JWT удобны, но многие инциденты происходят из-за предсказуемых ошибок. Относитесь к JWT как к наличным деньгам: кто получил — тот может потратить.
Если токен живёт дни или недели, утечка даёт атакующему всё это окно. Предпочитайте короткоживущие access-токены (минуты) и обновляйте их через безопасный механизм. Для «запомнить меня» используйте refresh-токены и серверные проверки.
Подпись недостаточна. Проверяйте iss и aud, валидируйте временные claims, такие как exp и nbf.
Декодирование — это не верификация. Всегда проверяйте подпись на сервере и применяйте авторизационные политики серверной стороны.
Избегайте размещения JWT в query-параметрах. Они могут попасть в историю браузера, логи, аналитические сервисы и referrer-заголовки.
Используйте Authorization: Bearer ... вместо этого.
Предполагайте, что ключи и токены могут утечь. Проводите ротацию signing-ключей, используйте kid для плавной ротации и имейте стратегию отзыва (короткие сроки жизни + возможность отключать аккаунты/сессии). Для советов по хранению смотрите /blog/where-to-store-jwts-safely.
JWT полезны, но не всегда лучший выбор. Вопрос: приносит ли вам пользу самодостаточный токен, который можно проверить без обращения к базе при каждом запросе?
Для традиционных серверно-рендеренных приложений, где важно простое инвалидирование, серверные сессии с HttpOnly cookies чаще проще и безопаснее.
Выбирайте JWT, если вам нужна статeless-проверка между сервисами и вы можете держать токены короткоживущими.
Избегайте JWT, если нужна мгновенная отзывность, вы собираетесь помещать чувствительные данные в токен или можете использовать cookie-сессии без неудобств.
Проверяйте правильный ключ и ожидаемый алгоритм. Отклоняйте неверные подписи — никаких исключений.
exp (срок действия)Убедитесь, что токен не просрочен.
nbf (not before)Если присутствует, убедитесь, что токен не используется раньше времени.
aud (audience)Подтвердите, что токен предназначен для вашего API/сервиса.
iss (issuer)Подтвердите, что токен выпущен ожидаемым издателем.
Проверяйте формат токена, максимальный размер и отвергайте неожиданные типы claims, чтобы снизить риск пограничных ошибок.
HS256 (симметричный ключ): один общий секрет для подписи и проверки.
RS256 / ES256 (асимметричные ключи): приватный ключ подписывает; публичный ключ проверяет.
Правило: если более одной независимой системы должна проверять токены (или вы не полностью доверяете каждому верификатору), предпочитайте RS256/ES256.
iss, aud, user ID только если политика позволяет).JWT зашифрован?
Не по умолчанию. Большинство JWT подписаны, но не зашифрованы — содержимое читаемо при наличии токена. Используйте JWE или не храните чувствительные данные в JWT.
Можно ли отозвать JWT?
Сложно, если вы полагаетесь только на самодостаточные access-токены. Распространённые подходы: короткоживущие access-токены, deny-list в критичных случаях, или refresh-токены с ротацией.
Какой должен быть срок exp?
Как можно короче, при условии приемлемого UX и архитектуры. Многие API используют минуты для access-токенов и refresh-токены для продолжительных сессий.
Если вы внедряете JWT-аутентификацию в новый API или SPA, много работы повторяется: подключение middleware, проверка iss/aud/exp, установка флагов cookie и исключение обработки токенов в логах.
С Koder.ai вы можете быстро прототипировать веб-приложение (React), бэкенд (Go + PostgreSQL) или Flutter-приложение через чат-ориентированный рабочий процесс — затем итеративно планировать, использовать снимки и откаты при отладке безопасности и экспортировать исходный код, когда будете готовы. Это практичный способ ускорить реализацию JWT-аутентификации, сохраняя контроль над логикой верификации, стратегией ротации ключей и настройками деплоя (включая кастомные домены).
JWT (JSON Web Token) — это компактная, URL-безопасная строка, которая несёт «claims» (поля данных) и может быть проверена сервером. Обычно её отправляют в API-запросах через:
Authorization: Bearer <token>Главная идея: сервер может проверить целостность токена (по подписи) без необходимости хранить сессию для каждого запроса.
Аутентификация через сессии обычно хранит состояние на сервере (запись сессии, идентифицируемая cookie/ID сессии). При JWT-аутентификации клиент прикладывает подписанный токен к каждому запросу, а API его валидирует.
JWT популярны для API и распределённых приложений, потому что проверку можно выполнить локально, уменьшая потребность в общем хранилище сессий.
«Бессерверность» не означает отсутствие серверных проверок: часто добавляют deny-list, проверки статуса пользователя или обработку ротации ключей.
JWT состоит из трёх частей Base64URL-кодированных и разделённых точками:
header.payload.signatureHeader описывает алгоритм подписи, payload содержит claims (например, sub, exp, aud), а подпись позволяет серверу обнаружить подделку.
Нет. Стандартные JWT обычно подписаны, но не зашифрованы.
Если нужна конфиденциальность, используйте JWE (шифрованные токены) или храните чувствительные данные на сервере, оставляя в токене только ссылку/ID.
Подпись позволяет серверу убедиться, что токен не был изменён и его выпустил доверенный подписант.
Она не даёт:
exp.Относитесь к токену как к учетным данным: если он скомрометирован, его можно воспроизвести до истечения срока действия.
alg указывает алгоритм, использованный для подписи (например, HS256 или RS256). kid — идентификатор ключа, помогающий подобрать правильный ключ при ротации.
Рекомендации по безопасности:
Начните со стандартных зарегистрированных claims и держите собственные поля минимальными.
Частые зарегистрированные claims:
JWT — это формат токена; OAuth 2.0 и OpenID Connect — протоколы.
Типичное соответствие:
Важно: не используйте ID token для вызова API просто потому, что он «выглядит как JWT».
Для браузерных приложений распространённые варианты хранения:
Минимум проверок при валидации JWT:
exp (не истёк)iss (ожидаемый издатель)aud (предназначен для вашего API)nbf (если есть)Практические дополнения:
alg.alg: "none".kid приводить к небезопасному поиску ключа.iss (issuer) — кто выпустил токенsub (subject) — субъект / идентификатор пользователяaud (audience) — для кого предназначен токен (API)exp (expiration) — время окончания действияiat (issued at) — время выпускаnbf (not before) — токен не пригоден до этого времениИзбегайте хранения секретов и чувствительных персональных данных в payload: всё, что в токене — читаемо при утечке.
HttpOnly, Secure и SameSite и при необходимости CSRF-токены для изменяющих состояние запросов.В любом случае держите access-токены короткоживущими и минимизируйте права.