Коротко о JWT

  • Михаил
  • 8 мин. на прочтение
  • 65
  • 05 Sep 2023
  • 05 Sep 2023

Есть такая штука, называется JWT - JSON Web Token. По сути это способ (стандарт) обернуть данные (payload) в подписанный пакет. В основном это используется для обмена данными, например авторизационными. Рассмотрим как это работает на простом примере авторизации.

  • Пользователь аутентифицируется с использованием login/пароля (АУТЕНТИФИКАЦИЯ)
  • В ответ получает jwt - json web token. Далее по тексту jwt-токен или просто “токен”.
  • Когда пользователь хочет получить доступ к ресурсу, он отправляет токен
  • Сервер проверяет валидность токена и предоставляет доступ к ресурсу (АВТОРИЗАЦИЯ)

Важно понимать, что токен не содержит в себе никакой секретной информации. Чаще всего туда помещают информацию о пользователе (id, username, email, role). Эта информация может быть прочитана кем угодно. Подписывается токен для того, чтобы убедиться в том, что информация в токене не была подделана/изменена. Подписан токен может либо закрытым ключом, либо парой открытым/закрытым ключом.

JWT похож на SAML, но гораздо проще. На картинке ниже проиллюстрировано то, как выглядит JWT-токен, подписанный парой ключей, открытым и закрытым. JWT токен состоит из заголовка, данных и подписи (“HEADER”+”PAYLOAD”+”SIGNATURE”).

Как видите, структура JWT-токена очень проста.

Рассмотрим принцип использования JWT, описанный в начале, более подробно, приблизив его к реальности.

Действия, описанные далее, могут отличаться в зависимости от реализации программиста и использования разных протоколов аутентификации и авторизации. Описанная ниже логика и порядок действий даёт общее понимание того, как устроен процесс.

  • Пользователь аутентифицируется с использованием логин/пароля (АУТЕНТИФИКАЦИЯ)
    Если говорить про WEB, то как правило пользователь заходит на сайт (клиент) и вводит логин пароль в форму авторизации. Клиент отправляет авторизационные данные серверу аутентификации, задача которого проверить, что пользователь является тем, за кого он себя выдаёт сверив пару логин/пароль с тем, что находится в его базе данных. И в зависимости от результата проверки возвращает положительный или отрицательный ответ клиенту (web-приложению, куда пользователь ввёл логин/пароль). Этот процесс называется аутентификация. Не путать с авторизацией.
  • Пользователь получает JWT-токены
    Если пользователь успешно прошёл процесс аутентификации, то есть ввёл действительные логин и пароль, то клиент, получив положительный ответ от сервера аутентификации запрашивает у сервера, который выдаёт токен, пару токенов - AccessToken и RefreshToken. Далее я объясню, откуда вдруг взялся RefreshToken и зачем он нужен. Это не обязательно разные сервера. В самом простом клиент-серверном приложении, сервер и аутентифицирует, и сразу же выдаёт ключи пользователю. Так или иначе пользователь получает токен и как правило хранит его в браузере. Например, в HttpOnly-Cookie.
  • Когда пользователь хочет получить доступ к ресурсу, он отправляет токен
    Когда пользователь хочет получить доступ к ресурсу, он отправляет запрос на сервер и передаёт AccessToken. В случае с jwt это можно сделать с использованием схемы Bearer. Для этого в HTTP заголовке передаётся ключ “Authorization” со значением, содержащим ключевое слово “Bearer” и через пробел сам токен.
Authorization: Bearer <token>
  • Сервер проверяет валидность токена и предоставляет доступ к ресурсу (АВТОРИЗАЦИЯ)
    После того, как сервер получил токен, он проверяет его валидность и предоставляет доступ к ресурсу. И тут кроется самое интересное. Токен может быть не валиден по разным причинам. Например, он просрочен. Дело в том, что хранить токены длительное время - это не безопасно. В зависимости от чувствительности данных, к которым предоставляется доступ, время жизни токена может быть от нескольких секунд, до нескольких минут. В случае если токен не действителен, то сервер сообщает на клиент ошибку 401 (Unauthorized Error). В таком случае клиент может попросить пользователя ещё раз ввести логин пароль. 
    Но чтобы не делать это слишком часто, придумали RefreshToken. Время жизни RefreshToken уже гораздо больше. Например 30-60 дней. Когда пользователь первый раз получает пару AccessToken/RefreshToken, то RefreshToken сохраняется как в базе данных на стороне сервера, вместе с id пользователя или другим уникальным идентификатором, так и на стороне клиента(пользователя). Как правило это HttpOnly-Cookie, которая хранится в браузере. Если после отправки AccessToken клиент получает ошибку 401 (Unauthorized Error), он отправляет RefreshToken на обновление токенов (/api/refresh) и после валидации RefreshToken сервер предоставляет новую пару AccessToken/RefreshToken. Клиент их сохраняет и заново отправляет AccessToken. Если на этот раз валидация прошла успешно, то сервер предоставляет доступ к запрашиваемому ресурсу.  Если же и RefreshToken не прошёл проверку, то пользователя просят заново пройти процесс аутентификации - ввести логин/пароль и заново получить пару AccessToken/RefreshToken.

На картинке показана упрощённая схема описанного процесса.

Конечно схема авторизации может и должна быть гораздо сложнее. Серверное приложение может проверять статус активна или нет учётная запись. Позволяет ли роль пользователя получить доступ к ресурсу и т.д.. Должен быть механизм отзыва токенов. Но всё это относится к внутренней логике конкретного приложения.