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 база данных (в реальном Также в библиотеке
Redis клиент для Swift (iOS/macOS) – RediStack
GraphQL в C# (.NET): Полное руководство по библиотеке GraphQL.NET
Event Bus и паттерн Observer в JavaScript (Node.js) — создание гибких событийных систем
Очереди задач для PHP: RabbitMQ, Beanstalkd и Gearman