Как реализовать аутентификацию по JWT в Node.js + Express
JWT — это компактный способ передавать данные об идентификации пользователя между клиентом и сервером в виде зашифрованной (подписанной) строки.
Преимущества:
- Без состояния (stateless) — серверу не нужно хранить сессии в памяти или БД.
- Универсальность — один и тот же токен можно использовать между разными сервисами и языками.
- Гибкость хранения — клиент может хранить токен в
localStorage
,sessionStorage
или куках.
Типичный поток работы:
- Пользователь отправляет логин/пароль на сервер.
- Сервер проверяет данные и генерирует JWT с полезной нагрузкой (например,
userId
). - Клиент хранит токен и отправляет его в заголовке
Authorization: Bearer <token>
при каждом запросе. - Сервер на каждом запросе валидирует подпись и срок действия токена.
Установка и подготовка проекта
Создаём папку проекта и устанавливаем зависимости:
mkdir jwt-auth-example && cd jwt-auth-example
npm init -y
npm install express jsonwebtoken bcryptjs dotenv
npm install --save-dev nodemon
- express – HTTP-фреймворк.
- jsonwebtoken – создание и проверка JWT.
- bcryptjs – хеширование паролей.
- dotenv – хранение секретов в
.env
.
В package.json
добавим скрипт:
"scripts": {
"dev": "nodemon index.js"
}
Структура проекта
jwt-auth-example/
├─ index.js
├─ .env
└─ users.js # простая «база» пользователей
Файл .env
:
JWT_SECRET=supersecretkey
JWT_EXPIRES=1h
Простейшая «база данных»
Для наглядности и чтобы избежать лишнего усложнения создадим простую мок-базу users.
users.js
:
const bcrypt = require('bcryptjs');
const users = []; // временное хранилище
async function createUser(username, password) {
const hashed = await bcrypt.hash(password, 10);
users.push({ username, password: hashed });
}
async function findUser(username) {
return users.find(u => u.username === username);
}
module.exports = { createUser, findUser };
Сервер Express с регистрацией и логином
index.js
:
require('dotenv').config();
const express = require('express');
const jwt = require('jsonwebtoken');
const bcrypt = require('bcryptjs');
const { createUser, findUser } = require('./users');
const app = express();
app.use(express.json());
// Регистрация
app.post('/register', async (req, res) => {
const { username, password } = req.body;
if (await findUser(username))
return res.status(400).json({ message: 'User already exists' });
await createUser(username, password);
res.json({ message: 'User registered' });
});
// Логин
app.post('/login', async (req, res) => {
const { username, password } = req.body;
const user = await findUser(username);
if (!user) return res.status(401).json({ message: 'Invalid credentials' });
const match = await bcrypt.compare(password, user.password);
if (!match) return res.status(401).json({ message: 'Invalid credentials' });
const token = jwt.sign(
{ username },
process.env.JWT_SECRET,
{ expiresIn: process.env.JWT_EXPIRES }
);
res.json({ token });
});
// Middleware проверки токена
function authMiddleware(req, res, next) {
const authHeader = req.headers['authorization'];
const token = authHeader && authHeader.split(' ')[1];
if (!token) return res.sendStatus(401);
jwt.verify(token, process.env.JWT_SECRET, (err, user) => {
if (err) return res.sendStatus(403);
req.user = user; // в user лежит payload токена
next();
});
}
// Пример защищённого маршрута
app.get('/profile', authMiddleware, (req, res) => {
res.json({ message: `Hello, ${req.user.username}!` });
});
app.listen(3000, () => console.log('Server running on http://localhost:3000'));
Проверяем
- Регистрация:
POST http://localhost:3000/register
JSON:{"username":"alice","password":"secret"}
- Логин:
POST http://localhost:3000/login
→ получаем токен:
{"token":"eyJhbGciOi..."}
- Защищённый маршрут:
GET http://localhost:3000/profile
Заголовок:Authorization: Bearer <token>
Ответ:
{"message":"Hello, alice!"}
Практические советы
-
Хранение токена:
– В SPA обычноlocalStorage
илиsessionStorage
.
– Для защиты от XSS можно использовать httpOnly-куки. -
Обновление токена (refresh token):
В продакшене часто используют пару: короткоживущий access-token + долгоживущий refresh-token. -
Отзыв токена:
JWT по умолчанию нельзя «отозвать». Если нужно — храните список заблокированных токенов или используйте версионирование токенов в базе. -
HTTPS:
Всегда передавайте токены по защищённому соединению.
Вывод
JWT позволяет реализовать аутентификацию без сохранения сессий на сервере. В связке с Node.js и Express достаточно нескольких библиотек, чтобы развернуть рабочий прототип: хэшируем пароли, генерируем и проверяем токены, защищаем маршруты через middleware. Для реального продакшена добавьте хранение пользователей в БД, refresh-токены и обязательно используйте HTTPS.
Настроить мониторинг за 30 секунд
Надежные оповещения о даунтаймах. Без ложных срабатываний