Gernar
Frontend DeveloperБезопасность, HTTP и API

Интервью-вопрос

Как работает JWT

JWT это подписанный токен с данными и сроком действия. Вам важно понимать не только структуру токена, но и риски хранения, XSS, CSRF, refresh flow и logout.

Добавлен
Редакция

Подготовьте короткий ответ и пару деталей на случай уточняющих вопросов.

🐰0
🥚0

Мини-квиз

Проверка перед разбором

Несколько быстрых вопросов перед разбором. Так проще поймать места, которые только кажутся понятными.

Вопрос 1 из 60 правильно

Как лучше коротко объяснить структуру JWT?

Вы отвечаете на базовый вопрос и хотите сразу убрать риск неверного слова про шифрование.

Варианты ответа

Разбор

Разобраться, а не зазубрить

Дальше разбираем суть, типичные уточнения и места, где легко сказать лишнее или перепутать термины.

Базовая идея

JWT, JSON Web Token, это строка из трех частей, разделенных точками. Обычно она выглядит так:

header.payload.signature

header описывает тип токена и алгоритм подписи. payload содержит claims, например sub, exp, iat, роль или идентификатор tenant. signature считается по header и payload с секретом или приватным ключом, чтобы сервер мог заметить подделку.

В ответе сразу уточните: JWT не означает шифрование. Если токен не сделан как отдельный encrypted JWT, payload можно прочитать в браузере. Подпись защищает целостность, но не конфиденциальность.

Как проходит запрос с JWT

Типичный сценарий такой: пользователь логинится, сервер выдает access token, клиент прикладывает его к защищенным запросам, сервер проверяет подпись и claims. Если проверка прошла, API выполняет действие. Если срок истек или подпись неверная, API возвращает 401 или 403 в зависимости от причины.

Для вашего frontend-кода важно обработать не только успешный запрос, но и истечение токена. Плохой UX получается, когда приложение бесконечно повторяет запросы с истекшим JWT, запускает несколько refresh-запросов одновременно или молча показывает пустой экран.

Нормальный flow
  1. 1Пользователь логинится по HTTPS
  2. 2Сервер выдает короткий access token
  3. 3Клиент отправляет токен в <code>Authorization</code> или cookie
  4. 4Сервер проверяет подпись, срок и claims
  5. 5При <code>401</code> клиент запускает refresh flow или просит войти снова
Опасный flow
  1. 1Клиент хранит долгоживущий токен в <code>localStorage</code>
  2. 2UI доверяет роли после простого decode
  3. 3Сервер не проверяет <code>exp</code> или алгоритм
  4. 4Logout только очищает браузер, но токен остается валидным
  5. 5XSS или утечка логов дают доступ к API до конца срока токена

Что проверяет сервер

Сервер не должен просто декодировать payload. Нормальная проверка включает подпись, допустимый алгоритм, срок действия и важные claims. Часто проверяют exp, nbf, iss, aud и права пользователя.

На интервью подчеркните: клиент может прочитать токен, но не принимает окончательное решение о доступе. Сервер остается источником истины, потому что запрос к API можно отправить напрямую, минуя ваш интерфейс.

Как выбирать поведение на фронтенде

Как рассуждать про JWT в приложении

1Нужно просто показать имя или роль в интерфейсе?
Декодируйте payload только как подсказку для UX.
2Нужно разрешить действие или отдать приватные данные?
Пусть решение принимает сервер после проверки подписи, срока и прав.
3Токен должен переживать перезагрузку страницы?
Обсудите HttpOnly cookie или refresh flow. Не выбирайте localStorage автоматически.
4Нужен быстрый logout или отзыв доступа?
Нужна серверная опора: blacklist, версия сессии или отзыв refresh token.
5Несколько запросов одновременно получили 401?
Запустите один refresh. Остальные запросы пусть ждут результат или корректно отменяются. После провала refresh очищайте auth state и не показывайте приватный UI.

Если токен передается через заголовок, frontend обычно добавляет его к запросу как Bearer token. Пример ниже показывает только передачу токена. Это не рекомендация хранить его в конкретном месте.

async function loadProfile(accessToken: string) {
  const response = await fetch("/api/profile", {
    headers: {
      Authorization: `Bearer ${accessToken}`,
    },
  });

  if (response.status === 401) {
    // Запустить refresh flow или перевести пользователя на login.
    throw new Error("Session expired");
  }

  if (!response.ok) {
    throw new Error("Cannot load profile");
  }

  return response.json();
}

Не говорите, что такой код сам по себе безопасен. Безопасность зависит от того, где хранится токен, как закрыт XSS, есть ли HTTPS, как работает refresh и что делает сервер при проверке. В реальном UI еще нужны состояние загрузки, понятная ошибка, отмена устаревшего запроса через AbortController или другой механизм и защита от повторного retry после 401.

Хранение и основные риски

Что важно учесть во frontend-части

Payloadне секрет

Не кладите туда чувствительные данные. Пользователь может декодировать токен прямо в браузере.

localStorageXSS risk

JavaScript может прочитать токен. При XSS злоумышленник заберет его и будет вызывать API от имени пользователя.

HttpOnly cookieCSRF risk

Токен нельзя прочитать из JavaScript, но браузер сам отправляет cookie. Нужны <code>SameSite</code>, CSRF-токен или другая защита.

Долгий срок жизнибольше ущерб

Украденный токен дольше работает. Для access token обычно выбирают короткий срок и отдельный refresh flow.

Logoutне только clear

Очистка клиента не отзывает уже выданный JWT. Для строгого logout нужна серверная инвалидация.

Refresh flowrace risk

Если каждый <code>401</code> запускает свой refresh, приложение отправит лишние запросы, может перезаписать новый токен старым ответом и показать неверное состояние.

Частая ошибка в ответе: сразу обещать положить JWT в localStorage и отправлять его в каждом запросе. Это неполный ответ, потому что localStorage читается любым скриптом на странице. При XSS злоумышленник получает готовый bearer token.

HttpOnly cookie тоже не серебряная пуля. Она снижает риск кражи токена через JavaScript, но браузер отправляет cookie автоматически. Поэтому нужно думать про CSRF. Хороший ответ не выбирает вариант наугад, а объясняет модель угроз и компромисс.

Отдельно проговорите refresh flow. Если при каждом 401 делать новый refresh и сразу менять состояние пользователя, можно получить гонку, лишние сетевые вызовы и мигающий UI. Безопаснее централизовать refresh, повторять запрос один раз, отменять устаревшие запросы и очищать приватные данные после окончательной ошибки авторизации.

Logout, refresh token и отзыв доступа

JWT удобен тем, что сервер может проверить токен без постоянного чтения серверной сессии. Но у этого есть цена: уже выданный JWT трудно мгновенно отозвать, если он самодостаточен и валиден до exp.

На практике часто делают короткоживущий access token и refresh token. Access token живет недолго и используется для API. Refresh token хранится осторожнее и может быть отозван на сервере. Так при краже access token окно риска меньше, а logout можно связать с отзывом refresh token или версии сессии.

Практический вывод

Соберите короткий ответ так:

JWT это подписанный токен из header, payload и signature. Payload можно прочитать, поэтому там не должно быть секретов. Сервер проверяет подпись, срок действия и claims при каждом защищенном запросе. На фронтенде я бы отдельно обсудил, где хранить токен, как обрабатывать 401 без бесконечных retry, как работает refresh и что будет при logout.

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

Частые ошибки

Где обычно ошибаются

Проверьте формулировки, которые звучат уверенно, но на интервью быстро выдают пробелы.

  1. 1

    Называть JWT шифрованием

    Обычный JWT чаще подписан, а не зашифрован. Payload читается после base64url decode. Если вы кладете туда секрет, вы фактически публикуете его. Скажите, что подпись защищает от подделки, но не скрывает данные.
  2. 2

    Доверять decode на клиенте

    Фронтенд может декодировать токен для имени или роли в интерфейсе. Но это не проверка авторизации. Пользователь контролирует клиентскую среду, а API должен проверять доступ на сервере. Иначе закрытые данные можно получить прямым запросом.
  3. 3

    Хранить долгоживущий токен в localStorage

    localStorage доступен любому скрипту на странице. Если появится XSS, токен можно украсть и использовать вне браузера. Лучше уменьшать срок жизни access token, закрывать XSS и рассматривать HttpOnly cookie или хранение в памяти.
  4. 4

    Забывать про CSRF при cookie

    HttpOnly cookie защищает от чтения токена через JavaScript, но браузер все равно отправляет cookie автоматически. Если API принимает state-changing запросы без защиты, возможен CSRF. Нужны настройки SameSite, Secure и дополнительная проверка, если сценарий этого требует.
  5. 5

    Делать logout только на клиенте

    Если JWT остается валидным до exp, простое удаление из браузера не помогает при уже украденном токене. Для критичных систем нужен отзыв refresh token, blacklist или версия сессии. На интервью так вы покажете, что понимаете цену stateless-подхода.
  6. 6

    Запускать refresh для каждого 401

    При нескольких параллельных запросах можно получить гонку. Старый refresh-ответ перезапишет новый токен, UI мигнет logout-состоянием, а сеть получит лишнюю нагрузку. Безопаснее держать один refresh promise, повторять исходный запрос только один раз и при провале очищать auth state.

Follow-up

Что могут спросить дальше

Короткие ответы на вопросы, которыми проверяют понимание JWT, хранения токенов и рисков во frontend-приложении.

Живые ответы

Видео с похожим вопросом

Если найдем публичные интервью с таким вопросом, добавим их сюда. Их удобно смотреть после теории, чтобы свериться с живыми ответами.

Пока видео нет. Когда появятся подходящие публичные интервью, добавим их в этот блок, чтобы можно было сравнить разбор с тем, как отвечают реальные кандидаты.

Содержание