← Назад к вопросам

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

2.3 Middle🔥 191 комментариев
#JavaScript Core

Комментарии (1)

🐱
claude-haiku-4.5PrepBro AI3 апр. 2026 г.(ред.)

Ответ сгенерирован нейросетью и может содержать ошибки

Как работает JWT (JSON Web Token)

JWT - это стандарт для безопасной передачи информации между сторонами в виде JSON объекта. Он самоподтверждающийся и закодирован.

Структура JWT

JWT состоит из трех частей, разделенных точками:

eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c

[Header].[Payload].[Signature]

Часть 1: Header (Заголовок)

Описывает тип токена и алгоритм подписи:

// Декодированный header
{
  "alg": "HS256",  // Алгоритм подписи
  "typ": "JWT"     // Тип токена
}

// Base64URL кодируется
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9

Часть 2: Payload (Полезная нагрузка)

Содержит claims (утверждения) о пользователе:

// Декодированный payload
{
  "sub": "1234567890",      // Subject ID пользователя
  "name": "John Doe",       // Имя пользователя
  "iat": 1516239022,        // Issued at (время создания)
  "exp": 1516325422,        // Expiration time (время истечения)
  "iss": "example.com",     // Issuer (издатель)
  "role": "admin"           // Кастомные данные
}

// Base64URL кодируется
eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ

Часть 3: Signature (Подпись)

Убеждает, что токен не был изменен:

// На сервере с секретным ключом
const signature = HMACSHA256(
  base64UrlEncode(header) + "." +
  base64UrlEncode(payload),
  secretKey
);

// Результат
SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c

Как это работает на практике

1. Авторизация (Login)

// На фронтенде
async function login(email, password) {
  const response = await fetch("/api/v1/auth/login", {
    method: "POST",
    headers: { "Content-Type": "application/json" },
    body: JSON.stringify({ email, password })
  });

  const { access_token } = await response.json();

  // Сохраняем токен (в localStorage или Cookie)
  localStorage.setItem("token", access_token);
  
  return access_token;
}

2. Отправка запроса с токеном

// На фронтенде
async function fetchUserProfile() {
  const token = localStorage.getItem("token");

  const response = await fetch("/api/v1/users/me", {
    method: "GET",
    headers: {
      "Authorization": `Bearer ${token}`,
      "Content-Type": "application/json"
    }
  });

  if (response.status === 401) {
    // Токен истек или невалидный
    // Нужно заново авторизоваться
    logout();
  }

  return response.json();
}

3. Проверка на сервере

# На бэкенде (FastAPI)
import jwt
from datetime import datetime, timedelta

SECRET_KEY = "your-secret-key"
ALGORITHM = "HS256"

# Создание токена
def create_token(user_id: str):
    payload = {
        "sub": user_id,
        "iat": datetime.utcnow(),
        "exp": datetime.utcnow() + timedelta(hours=24)
    }
    token = jwt.encode(payload, SECRET_KEY, algorithm=ALGORITHM)
    return token

# Проверка токена
def verify_token(token: str):
    try:
        payload = jwt.decode(token, SECRET_KEY, algorithms=[ALGORITHM])
        user_id = payload.get("sub")
        if user_id is None:
            raise ValueError("Invalid token")
        return user_id
    except jwt.ExpiredSignatureError:
        raise ValueError("Token expired")
    except jwt.InvalidTokenError:
        raise ValueError("Invalid token")

Преимущества JWT

// 1. Независимость от состояния сервера
// Не нужно хранить сессии в БД

// 2. Масштабируемость
// Токен может проверить любой сервер, зная секрет

// 3. Мобильные приложения
// Удобно передавать в заголовке Authorization

// 4. CORS-дружественный
// Работает с различными доменами

// 5. Информация внутри токена
// Сразу видна информация о пользователе

Недостатки и меры безопасности

// Проблема 1: Токен видим в Base64 (не шифруется)
// Решение: используй HTTPS для передачи

// Проблема 2: Если украли токен, его нельзя отозвать
// Решение: установи короткое время жизни (15 минут)

// Проблема 3: При изменении пароля токен еще валиден
// Решение: сохраняй версию пароля в payload для проверки

// Правильное сохранение в браузере
const storeToken = (token) => {
  // ✅ В httpOnly cookie (безопаснее от XSS)
  // ❌ В localStorage (уязвимо для XSS)
  // ❌ В sessionStorage (тоже уязвимо)
  
  // Если используешь localStorage, добавь CSP headers
};

Refresh Token паттерн

// Два типа токенов для большей безопасности
const tokens = {
  access_token: "short-lived (15 min)",  // Для API запросов
  refresh_token: "long-lived (7 days)"   // Для получения новых access_token
};

// При истечении access_token
async function refreshAccessToken() {
  const refreshToken = localStorage.getItem("refresh_token");
  
  const response = await fetch("/api/v1/auth/refresh", {
    method: "POST",
    headers: { "Content-Type": "application/json" },
    body: JSON.stringify({ refresh_token: refreshToken })
  });

  const { access_token } = await response.json();
  localStorage.setItem("token", access_token);
  
  return access_token;
}

Ключевые моменты

  • JWT не шифруется, только подписывается
  • Проверка подписи гарантирует, что токен не был изменен
  • Всегда передавай JWT через HTTPS
  • Используй httpOnly cookies для большей безопасности
  • Установи разумное время истечения токена
  • Реализуй refresh token механизм для безопасности
Как работает JWT? | PrepBro