JsonWebToken для JavaScript (Node.js): полное руководство с примерами

Онлайн-тренажер Python для начинающих

Изучайте Python легко и без перегрузки теорией. Решайте практические задачи с автоматической проверкой, получайте подсказки на русском языке и пишите код прямо в браузере — без необходимости что-либо устанавливать.

Начать курс

JsonWebToken для JavaScript (Node.js): полное руководство с примерами

Что это и зачем нужна

Библиотека JsonWebToken (часто используется как jsonwebtoken или jwt) — это одна из самых популярных библиотек для работы с JSON Web Tokens (JWT) в среде Node.js. JWT представляет собой компактный и самодостаточный способ передачи информации между сторонами в виде JSON-объекта. Эта информация может быть проверена и ей можно доверять, поскольку она подписана цифровой подписью. JWT могут быть подписаны с использованием секретного ключа (алгоритм HMAC) или пары открытого/закрытого ключей (алгоритмы RSA или ECDSA).

Основное назначение библиотеки — реализация механизмов авторизации и аутентификации в веб-приложениях и API. Когда пользователь успешно входит в систему, сервер создает JWT и отправляет его клиенту. Клиент затем отправляет этот токен с каждым последующим запросом, что позволяет серверу проверять личность пользователя без необходимости хранить сессионные данные на сервере. Это делает JWT идеальным решением для создания RESTful API, микросервисных архитектур и одностраничных приложений (SPA).

Библиотека jsonwebtoken предоставляет полный набор инструментов для создания (sign), проверки (verify) и декодирования (decode) токенов. Она поддерживает все стандартные алгоритмы подписи, включая HS256, RS256, ES256, и позволяет гибко настраивать время жизни токена, добавлять кастомные поля (claims) и работать с публичными/приватными ключами. Благодаря своей надежности и простоте, эта библиотека используется в тысячах проектов по всему миру и является стандартом де-факто для работы с JWT в экосистеме Node.js.

Установка

Для установки библиотеки JsonWebToken в ваш проект Node.js выполните следующую команду в терминале:

npm install jsonwebtoken

Если вы используете Yarn:

yarn add jsonwebtoken

После установки вы можете импортировать библиотеку в свой код:

const jwt = require('jsonwebtoken');
// или для ES-модулей:
// import jwt from 'jsonwebtoken';

Быстрый старт — минимальный рабочий пример

Давайте создадим простейший пример, демонстрирующий создание и проверку JWT токена:

const jwt = require('jsonwebtoken');

// Секретный ключ (в реальном проекте храните его в .env)
const secretKey = 'my-super-secret-key-123';

// Данные, которые мы хотим закодировать в токене (payload)
const payload = {
  userId: 12345,
  username: 'john_doe',
  role: 'user'
};

// 1. СОЗДАНИЕ ТОКЕНА
const token = jwt.sign(payload, secretKey, { expiresIn: '1h' });
console.log('Созданный токен:', token);

// 2. ПРОВЕРКА ТОКЕНА
try {
  const decoded = jwt.verify(token, secretKey);
  console.log('Декодированные данные:', decoded);
  // Вывод: { userId: 12345, username: 'john_doe', role: 'user', iat: ..., exp: ... }
} catch (err) {
  console.error('Ошибка проверки токена:', err.message);
}

// 3. ДЕКОДИРОВАНИЕ БЕЗ ПРОВЕРКИ ПОДПИСИ (НЕ РЕКОМЕНДУЕТСЯ для авторизации!)
const decodedWithoutVerify = jwt.decode(token);
console.log('Декодировано без проверки:', decodedWithoutVerify);

Этот пример показывает три основных операции: создание токена с помощью sign(), проверку его подлинности с помощью verify() и простое декодирование без проверки подписи с помощью decode().

Основные методы/функции/классы

1. jwt.sign(payload, secretOrPrivateKey, [options, callback])

Сигнатура: jwt.sign(payload: Object|Buffer, secretOrPrivateKey: string|Buffer, options?: Object, callback?: Function) => string|void

Что делает: Создает (подписывает) JWT токен. Принимает payload (данные), секретный ключ и опциональные настройки. Если передан callback, работает асинхронно.

const jwt = require('jsonwebtoken');
const secret = 'my-secret';

// Синхронное создание
const tokenSync = jwt.sign({ userId: 1 }, secret, { expiresIn: '2 days' });
console.log('Синхронный токен:', tokenSync);

// Асинхронное создание с callback
jwt.sign({ userId: 2 }, secret, { expiresIn: '1h' }, (err, token) => {
  if (err) {
    console.error('Ошибка:', err);
  } else {
    console.log('Асинхронный токен:', token);
  }
});

// Создание с кастомными claims
const customToken = jwt.sign(
  { 
    sub: '1234567890',
    name: 'John Doe',
    admin: true 
  },
  secret,
  { 
    issuer: 'myapp.com',
    audience: 'myapp-users',
    algorithm: 'HS256'
  }
);
console.log('Токен с кастомными claims:', customToken);

2. jwt.verify(token, secretOrPublicKey, [options, callback])

Сигнатура: jwt.verify(token: string, secretOrPublicKey: string|Buffer, options?: Object, callback?: Function) => Object|void

Что делает: Проверяет подпись токена и возвращает декодированный payload. Если токен недействителен (просрочен, неверная подпись), выбрасывает ошибку.

const jwt = require('jsonwebtoken');
const secret = 'my-secret';
const token = jwt.sign({ userId: 1 }, secret, { expiresIn: '1h' });

// Успешная верификация
try {
  const decoded = jwt.verify(token, secret);
  console.log('Успешно проверено:', decoded);
} catch (err) {
  console.error('Ошибка верификации:', err.message);
}

// Верификация с опциями
try {
  const decoded = jwt.verify(token, secret, {
    algorithms: ['HS256'],
    issuer: 'myapp.com',
    maxAge: '2h'
  });
  console.log('Проверено с опциями:', decoded);
} catch (err) {
  console.error('Ошибка:', err.message);
}

// Асинхронная верификация
jwt.verify(token, secret, (err, decoded) => {
  if (err) {
    console.error('Асинхронная ошибка:', err.message);
  } else {
    console.log('Асинхронно проверено:', decoded);
  }
});

3. jwt.decode(token, [options])

Сигнатура: jwt.decode(token: string, options?: Object) => Object|null

Что делает: Декодирует токен без проверки подписи. Возвращает payload или null, если токен невалидный. Внимание: не проверяет подпись, используйте только для отладки или когда подпись не важна.

const jwt = require('jsonwebtoken');
const secret = 'my-secret';
const token = jwt.sign({ userId: 1, role: 'admin' }, secret);

// Декодирование (без проверки подписи)
const decoded = jwt.decode(token);
console.log('Декодированный payload:', decoded);
// Вывод: { userId: 1, role: 'admin', iat: ..., exp: ... }

// Декодирование с опцией complete (возвращает header, payload, signature)
const complete = jwt.decode(token, { complete: true });
console.log('Полная структура:', complete);
// Вывод: { header: { alg: 'HS256', typ: 'JWT' }, payload: {...}, signature: '...' }

// Декодирование невалидного токена
const invalid = jwt.decode('invalid-token-string');
console.log('Невалидный токен:', invalid); // null

4. jwt.sign() с алгоритмом RS256 (асимметричное шифрование)

Сигнатура: Аналогична jwt.sign(), но вместо секретного ключа используется приватный ключ RSA

Что делает: Позволяет создавать токены с использованием асимметричного шифрования (пара ключей: приватный для подписи, публичный для проверки).

const jwt = require('jsonwebtoken');
const fs = require('fs');

// Загрузка ключей (в реальном проекте храните их безопасно)
const privateKey = fs.readFileSync('private.key', 'utf8');
const publicKey = fs.readFileSync('public.key', 'utf8');

// Создание токена с RS256
const payload = { userId: 1, role: 'admin' };
const token = jwt.sign(payload, privateKey, { 
  algorithm: 'RS256',
  expiresIn: '1h'
});
console.log('RS256 токен:', token);

// Проверка токена с публичным ключом
try {
  const decoded = jwt.verify(token, publicKey, { algorithms: ['RS256'] });
  console.log('Проверено с публичным ключом:', decoded);
} catch (err) {
  console.error('Ошибка:', err.message);
}

5. jwt.verify() с опциями (algorithms, audience, issuer)

Сигнатура: jwt.verify(token, secretOrPublicKey, options)

Что делает: Позволяет задать дополнительные проверки: какие алгоритмы разрешены, проверка audience (получателя) и issuer (издателя) токена.

const jwt = require('jsonwebtoken');
const secret = 'my-secret';

const token = jwt.sign(
  { 
    sub: 'user123',
    role: 'user'
  },
  secret,
  { 
    issuer: 'auth.myapp.com',
    audience: 'api.myapp.com',
    expiresIn: '1h'
  }
);

// Проверка с полными опциями
try {
  const decoded = jwt.verify(token, secret, {
    algorithms: ['HS256', 'HS384'],
    issuer: 'auth.myapp.com',
    audience: 'api.myapp.com',
    clockTolerance: 30 // допуск по времени в секундах
  });
  console.log('Токен прошел все проверки:', decoded);
} catch (err) {
  console.error('Проверка не пройдена:', err.message);
}

6. jwt.sign() с использованием Buffer для payload

Сигнатура: jwt.sign(payload: Buffer, secretOrPrivateKey, options)

Что делает: Позволяет передавать payload в виде Buffer (например, для бинарных данных или когда нужно избежать автоматической сериализации).

const jwt = require('jsonwebtoken');
const secret = 'my-secret';

// Создание payload как Buffer
const payloadBuffer = Buffer.from(JSON.stringify({ userId: 1, data: 'test' }));
const token = jwt.sign(payloadBuffer, secret, { expiresIn: '1h' });
console.log('Токен из Buffer:', token);

// Проверка
const decoded = jwt.verify(token, secret);
console.log('Декодировано:', decoded);

7. jwt.sign() с кастомным заголовком (header)

Сигнатура: jwt.sign(payload, secretOrPrivateKey, { header: { ... } })

Что делает: Позволяет задать кастомные поля в заголовке JWT (например, указать тип токена или добавить пользовательские метаданные).

const jwt = require('jsonwebtoken');
const secret = 'my-secret';

const token = jwt.sign(
  { userId: 1 },
  secret,
  {
    header: {
      typ: 'JWT',
      alg: 'HS256',
      kid: 'key-id-123', // Key ID для ротации ключей
      custom: 'custom-header-value'
    },
    expiresIn: '1h'
  }
);
console.log('Токен с кастомным заголовком:', token);

// Проверка с complete: true чтобы увидеть заголовок
const decoded = jwt.decode(token, { complete: true });
console.log('Заголовок:', decoded.header);

8. jwt.verify() с обработкой различных ошибок

Сигнатура: jwt.verify(token, secretOrPublicKey, callback)

Что делает: Позволяет обрабатывать специфические ошибки JWT (TokenExpiredError, JsonWebTokenError, NotBeforeError) для более точной диагностики.

const jwt = require('jsonwebtoken');
const secret = 'my-secret';

// Создаем токен с коротким сроком жизни
const token = jwt.sign({ userId: 1 }, secret, { expiresIn: '1s' });

// Ждем 2 секунды, чтобы токен истек
setTimeout(() => {
  jwt.verify(token, secret, (err, decoded) => {
    if (err) {
      if (err instanceof jwt.TokenExpiredError) {
        console.error('Токен истек:', err.expiredAt);
      } else if (err instanceof jwt.JsonWebTokenError) {
        console.error('Неверный JWT:', err.message);
      } else if (err instanceof jwt.NotBeforeError) {
        console.error('Токен еще не активен:', err.date);
      } else {
        console.error('Другая ошибка:', err.message);
      }
    } else {
      console.log('Токен валиден:', decoded);
    }
  });
}, 2000);

Реальный практический пример (100-200 строк кода)

Ниже представлен полноценный пример реализации аутентификации с использованием JWT в простом Express-приложении. Этот код демонстрирует регистрацию, вход, защиту маршрутов и обновление токенов.

const express = require('express');
const jwt = require('jsonwebtoken');
const bcrypt = require('bcrypt'); // Для хеширования паролей
const app = express();

app.use(express.json());

// Конфигурация
const ACCESS_TOKEN_SECRET = process.env.ACCESS_TOKEN_SECRET || 'access-secret-key-123';
const REFRESH_TOKEN_SECRET = process.env.REFRESH_TOKEN_SECRET || 'refresh-secret-key-456';
const ACCESS_TOKEN_EXPIRY = '15m';
const REFRESH_TOKEN_EXPIRY = '7d';

// Простая in-memory база данных (в реальном                    

Рекомендаций