PurpleSchool — курсы программирования онлайн
  • Пути
    • Frontend React разработчик
    • Frontend Vue разработчик
    • Backend разработчик Node.js
    • Fullstack разработчик React / Node.js
    • Mobile разработчик React Native
    • Backend разработчик Golang
    • Devops инженер
    • Backend разработчик Python
  • AI для кодаНовое
  • О нас
    • Отзывы
    • Реферальная программа
    • О компании
    • Контакты
  • Иконка открытия меню
    • Сообщество
    • PurpleПлюс
    • AI Собеседование
    • AI тренажёр
    • Проекты
PurpleSchool — платформа бесплатных roadmap и курсов для разработчиков
ютуб иконка
Telegram иконка
VK иконка
VK иконка
Курсы
ГлавнаяКаталог курсовFrontendBackendFullstack
Практика
КарьераПроектыPurpleПлюс
Материалы
БлогБаза знаний
Документы
Договор офертаПолитика конфиденциальностиПроверка сертификатаМиграция курсовРеферальная программа
Реквизиты
ИП Ларичев Антон АндреевичИНН 773373765379contact@purpleschool.ru

PurpleSchool © 2020 -2026 Все права защищены

  • Курсы
    • FrontendИконка стрелки
    • AI разработкаИконка стрелки
    • BackendИконка стрелки
    • DevOpsИконка стрелки
    • MobileИконка стрелки
    • ТестированиеИконка стрелки
    • Soft-skillsИконка стрелки
    • ДизайнИконка стрелки
    Иконка слояПерейти в каталог курсов
  • Бесплатно
    • Курсы
    • JavaScript Основы разработкиPython Основы PythonCSS CSS FlexboxКарта развитияВопросы для собеседований
    • База знанийИконка стрелки
    • Новостные рассылкиИконка стрелки
  • PurpleSchool — курсы программирования онлайн
    • AI для кодаНовое
    • Сообщество
    • PurpleПлюс
    • AI Собеседование
    • AI тренажёр
    • Проекты
    Главная
    Сообщество
    JWT аутентификация в Node.js: access и refresh токены

    JWT аутентификация в Node.js: access и refresh токены

    Аватар автора JWT аутентификация в Node.js: access и refresh токены

    Антон Ларичев

    Иконка календаря27 мая 2026
    Node.jsJWTАутентификацияБезопасностьBackendmiddleИконка уровня middle
    Картинка поста JWT аутентификация в Node.js: access и refresh токены

    Введение

    JWT (JSON Web Token) — это компактный стандарт передачи данных между сторонами в виде подписанного JSON-объекта. В Node.js JWT часто используется для реализации аутентификации в REST API и микросервисах: сервер не хранит сессии, а доверяет токену, проверяя его подпись.

    Классическая схема включает два типа токенов: access — короткоживущий, используется для доступа к защищённым ресурсам, и refresh — долгоживущий, нужен для обновления access без повторного ввода пароля. Такой подход снижает риски: если access утечёт, окно атаки ограничено его временем жизни.

    В статье разберём генерацию, проверку и ротацию токенов, а также типичные ошибки реализации.

    Структура JWT

    Токен состоит из трёх частей, разделённых точкой: header.payload.signature. Header описывает алгоритм подписи, payload содержит claims (sub, iat, exp и кастомные поля), signature — криптографическая подпись HMAC или RSA.

    Важно понимать: payload не шифруется, а только кодируется в base64url. Не кладите туда пароли, ключи или персональные данные. Подпись лишь гарантирует, что токен не был изменён.

    Подготовка проекта

    Установим зависимости:

    npm install express jsonwebtoken bcrypt cookie-parser
    npm install --save-dev @types/jsonwebtoken @types/express typescript
    

    В переменные окружения вынесем секреты:

    JWT_ACCESS_SECRET=replace_with_long_random_string
    JWT_REFRESH_SECRET=another_long_random_string
    ACCESS_TTL=15m
    REFRESH_TTL=30d
    

    Генерируйте секреты длиной не менее 32 байт, например через openssl rand -hex 32. Никогда не коммитьте их в репозиторий.

    Генерация access и refresh токенов

    Создадим сервис для работы с токенами:

    import jwt from 'jsonwebtoken';
    
    export interface TokenPayload {
      userId: string;
      email: string;
    }
    
    export class TokenService {
      // Создаём пару токенов на основе данных пользователя
      generateTokens(payload: TokenPayload) {
        const accessToken = jwt.sign(payload, process.env.JWT_ACCESS_SECRET!, {
          expiresIn: process.env.ACCESS_TTL,
        });
    
        const refreshToken = jwt.sign(payload, process.env.JWT_REFRESH_SECRET!, {
          expiresIn: process.env.REFRESH_TTL,
        });
    
        return { accessToken, refreshToken };
      }
    
      // Проверка access-токена: вернёт payload или null
      validateAccess(token: string): TokenPayload | null {
        try {
          return jwt.verify(token, process.env.JWT_ACCESS_SECRET!) as TokenPayload;
        } catch {
          return null;
        }
      }
    
      validateRefresh(token: string): TokenPayload | null {
        try {
          return jwt.verify(token, process.env.JWT_REFRESH_SECRET!) as TokenPayload;
        } catch {
          return null;
        }
      }
    }
    

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

    Эндпоинты логина и обновления

    При логине проверяем пароль через bcrypt и выдаём пару токенов. Refresh кладём в httpOnly cookie, access возвращаем в теле ответа:

    import { Router } from 'express';
    import bcrypt from 'bcrypt';
    
    const router = Router();
    const tokens = new TokenService();
    
    router.post('/login', async (req, res) => {
      const { email, password } = req.body;
      const user = await userRepository.findByEmail(email);
    
      if (!user || !(await bcrypt.compare(password, user.passwordHash))) {
        return res.status(401).json({ message: 'Неверные учётные данные' });
      }
    
      const pair = tokens.generateTokens({ userId: user.id, email: user.email });
      await refreshRepository.save(user.id, pair.refreshToken);
    
      // httpOnly защищает refresh от чтения через JavaScript
      res.cookie('refreshToken', pair.refreshToken, {
        httpOnly: true,
        secure: true,
        sameSite: 'strict',
        maxAge: 30 * 24 * 60 * 60 * 1000,
      });
    
      res.json({ accessToken: pair.accessToken });
    });
    

    Отдельный эндпоинт /refresh принимает refresh из cookie, проверяет его наличие в БД (ротация) и выдаёт новую пару:

    router.post('/refresh', async (req, res) => {
      const token = req.cookies.refreshToken;
      const payload = tokens.validateRefresh(token);
      const stored = await refreshRepository.find(token);
    
      if (!payload || !stored) {
        return res.status(401).json({ message: 'Refresh недействителен' });
      }
    
      // Удаляем старый токен, чтобы исключить повторное использование
      await refreshRepository.delete(token);
      const pair = tokens.generateTokens({ userId: payload.userId, email: payload.email });
      await refreshRepository.save(payload.userId, pair.refreshToken);
    
      res.cookie('refreshToken', pair.refreshToken, { httpOnly: true, secure: true, sameSite: 'strict' });
      res.json({ accessToken: pair.accessToken });
    });
    

    Middleware для защищённых маршрутов

    export function authGuard(req, res, next) {
      const header = req.headers.authorization;
      if (!header?.startsWith('Bearer ')) {
        return res.status(401).json({ message: 'Нет токена' });
      }
    
      const payload = tokens.validateAccess(header.slice(7));
      if (!payload) {
        return res.status(401).json({ message: 'Токен истёк или повреждён' });
      }
    
      req.user = payload;
      next();
    }
    

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

    • Хранение refresh в localStorage. Любой XSS моментально украдёт токен. Используйте httpOnly cookie с флагами Secure и SameSite.
    • Одинаковый секрет для access и refresh. Усложняет ротацию и снижает безопасность.
    • Отсутствие ротации refresh. Без удаления старого токена украденный refresh работает бессрочно.
    • Чувствительные данные в payload. Помните, что payload читается без ключа.
    • Слишком длинный TTL access. Делайте его коротким: 5–15 минут.
    • Игнорирование алгоритма none. Всегда указывайте конкретный алгоритм при verify через параметр algorithms.

    Заключение

    Схема access + refresh даёт баланс между удобством пользователя и безопасностью. Короткий access ограничивает урон от утечки, refresh с ротацией и httpOnly cookie защищает долгоживущую сессию. Главное — хранить секреты в env, использовать разные ключи для двух токенов и обязательно вести таблицу выданных refresh для отзыва. Такой подход легко масштабируется на микросервисы и подходит для большинства production-задач на Node.js.

    Иконка глаза421

    Комментарии

    0

    Постройте личный план изучения Next.js 15 - с нуля, React TypeScript, Hooks, SSR и CSS Grid до уровня Middle — бесплатно!

    Next.js 15 - с нуля, React TypeScript, Hooks, SSR и CSS Grid — часть карты развития Frontend

    • step100+ шагов развития
    • lessons30 бесплатных лекций
    • lessons300 бонусных рублей на счет

    Бесплатные лекции

    Лучшие курсы по теме

    изображение курса

    Vue 3 и Pinia

    Антон Ларичев
    AI-тренажерыAI-тренажеры
    Практика в студииПрактика в студии
    Гарантия
    Бонусы
    иконка звёздочки рейтинга4.8
    3 999 ₽ 6 990 ₽
    Подробнее
    изображение курса

    Nuxt

    Антон Ларичев
    AI-тренажерыAI-тренажеры
    Практика в студииПрактика в студии
    Гарантия
    Бонусы
    иконка звёздочки рейтинга5.0
    3 999 ₽ 6 990 ₽
    Подробнее
    изображение курса

    Feature-Sliced Design

    Антон Ларичев
    AI-тренажерыAI-тренажеры
    Практика в студииПрактика в студии
    Гарантия
    Бонусы
    иконка звёздочки рейтинга4.5
    3 999 ₽ 6 990 ₽
    Подробнее

    Похожие статьи

    Картинка поста JWT токены: структура, работа и аутентификация в Node.js
    Иконка аватараАнтон
    Иконка календаря01 июля 2026
    JWTаутентификацияNode.js+ 2juniorИконка уровня junior

    JWT токены: структура, работа и аутентификация в Node.js

    JWT токены — стандарт для безопасной передачи данных между клиентом и сервером. Разбираем структуру, реализацию и частые ошибки.

    Иконка чипа0
    Иконка глаза164
    Иконка комментариев0
    Картинка поста CI/CD с GitHub Actions: автоматизация деплоя для начинающих
    Иконка аватараАнтон
    Иконка календаря03 июля 2026
    CI/CDGitHub ActionsDevOps+ 2juniorИконка уровня junior

    CI/CD с GitHub Actions: автоматизация деплоя для начинающих

    CI/CD с GitHub Actions: пошаговая настройка pipeline для автоматического тестирования и деплоя Node.js-приложений без сторонних сервисов.

    Иконка чипа0
    Иконка глаза118
    Иконка комментариев0
    Картинка поста Что такое CORS и как его настроить: полное руководство
    Иконка аватараАнтон
    Иконка календаря29 июня 2026
    CORSHTTPбраузер+ 2juniorИконка уровня junior

    Что такое CORS и как его настроить: полное руководство

    CORS — механизм безопасности браузера, ограничивающий запросы между разными источниками. Разбираем, как работает и как настроить на сервере.

    Иконка чипа0
    Иконка глаза191
    Иконка комментариев0
    Иконка чипа0