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 тренажёр
    • Проекты
    Главная
    Сообщество
    Авторизация и аутентификация в Node.js: JWT, OAuth2 и сессии

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

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

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

    Иконка календаря11 июня 2026
    Node.jsБезопасностьJWTOAuth2АутентификацияmiddleИконка уровня middle
    Картинка поста Авторизация и аутентификация в Node.js: JWT, OAuth2 и сессии

    Введение

    Аутентификация отвечает на вопрос «кто вы?», а авторизация — «что вам разрешено?». Эти два слоя часто путают, но проектируются они по-разному: первый проверяет подлинность пользователя, второй — его права. В Node.js для решения этих задач исторически сложились три подхода: серверные сессии, JWT и делегированная авторизация через OAuth2. Каждый имеет свою область применимости, и выбор зависит от модели угроз, архитектуры и удобства эксплуатации.

    В статье разберём, как реализовать каждый подход на Express, где у них слабые места и как их комбинировать. Примеры намеренно минималистичные — чтобы сосредоточиться на сути, а не на обвязке.

    Серверные сессии

    Классическая схема: сервер хранит состояние сессии (в Redis, БД или памяти), а клиенту отдаёт только идентификатор в HttpOnly-куке. Это безопасно по умолчанию: JS на клиенте к куке не достучится, отзыв сессии — это просто удаление записи в хранилище.

    import express from 'express';
    import session from 'express-session';
    import RedisStore from 'connect-redis';
    import { createClient } from 'redis';
    
    const redisClient = createClient({ url: process.env.REDIS_URL });
    await redisClient.connect();
    
    const app = express();
    app.use(express.json());
    
    app.use(session({
      store: new RedisStore({ client: redisClient }),
      secret: process.env.SESSION_SECRET,
      resave: false,
      saveUninitialized: false,
      cookie: {
        httpOnly: true,        // недоступна из JS
        secure: true,          // только по HTTPS
        sameSite: 'lax',       // защита от большинства CSRF
        maxAge: 1000 * 60 * 60 * 24 // сутки
      }
    }));
    
    app.post('/login', async (req, res) => {
      const user = await verifyCredentials(req.body.email, req.body.password);
      if (!user) return res.status(401).end();
      // сохраняем минимум данных — остальное подтянем из БД
      req.session.userId = user.id;
      res.json({ ok: true });
    });
    

    Плюсы: моментальный отзыв доступа, простая ротация, состояние всегда актуально. Минусы: нужна общая для всех инстансов сессионная БД, требуется CSRF-защита для небезопасных методов.

    JWT: токены без состояния

    JWT (JSON Web Token) — это подписанный токен, который сам содержит данные о пользователе. Сервер не хранит сессию: достаточно проверить подпись и срок действия. Удобно для распределённых API и микросервисов.

    import jwt from 'jsonwebtoken';
    
    const ACCESS_TTL = '15m';
    const REFRESH_TTL = '30d';
    
    function issueTokens(user) {
      const access = jwt.sign(
        { sub: user.id, role: user.role },
        process.env.JWT_ACCESS_SECRET,
        { expiresIn: ACCESS_TTL }
      );
      const refresh = jwt.sign(
        { sub: user.id, jti: crypto.randomUUID() },
        process.env.JWT_REFRESH_SECRET,
        { expiresIn: REFRESH_TTL }
      );
      return { access, refresh };
    }
    
    // middleware для защищённых маршрутов
    function authRequired(req, res, next) {
      const header = req.headers.authorization ?? '';
      const token = header.startsWith('Bearer ') ? header.slice(7) : null;
      if (!token) return res.status(401).end();
      try {
        req.user = jwt.verify(token, process.env.JWT_ACCESS_SECRET);
        next();
      } catch {
        res.status(401).end();
      }
    }
    

    Главное правило — короткоживущий access-токен и отдельный refresh с возможностью отзыва. Refresh-токен лучше хранить в HttpOnly-куке и записывать его jti в БД, чтобы можно было инвалидировать конкретное устройство.

    Где хранить токены на клиенте

    Хранение JWT в localStorage — частый источник XSS-уязвимостей: любой инжектированный скрипт получит доступ к токену. Безопаснее держать access-токен в памяти JS-процесса, а refresh — в HttpOnly-куке с SameSite=Strict или Lax.

    OAuth2: делегированная авторизация

    OAuth2 нужен, когда вы хотите войти через GitHub, Google или Yandex, либо предоставить сторонним приложениям ограниченный доступ к вашему API. Это протокол получения access-токена от имени пользователя без передачи его пароля.

    Для веб-приложений подходит Authorization Code Flow с PKCE. Удобнее всего реализовать его через Passport.js или специализированные библиотеки.

    import passport from 'passport';
    import { Strategy as GitHubStrategy } from 'passport-github2';
    
    passport.use(new GitHubStrategy({
      clientID: process.env.GITHUB_CLIENT_ID,
      clientSecret: process.env.GITHUB_CLIENT_SECRET,
      callbackURL: '/auth/github/callback',
      scope: ['user:email']
    }, async (accessToken, refreshToken, profile, done) => {
      // ищем пользователя или создаём нового
      const user = await upsertUserByOAuth('github', profile);
      done(null, user);
    }));
    
    app.get('/auth/github', passport.authenticate('github'));
    
    app.get('/auth/github/callback',
      passport.authenticate('github', { failureRedirect: '/login' }),
      (req, res) => {
        // после успешного входа создаём свою сессию или JWT
        req.session.userId = req.user.id;
        res.redirect('/');
      }
    );
    

    Обратите внимание: OAuth2 решает только задачу получения токена от провайдера. После колбэка вы всё равно создаёте собственную сессию или выдаёте свой JWT — провайдерский access-токен наружу не пробрасывается.

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

    • Использование alg: none или слабого секрета для JWT. Подпись HS256 требует длинного случайного ключа, а лучше — пары RS256/ES256.
    • Длинный TTL у access-токена. Если токен живёт сутки, отозвать его без чёрного списка невозможно. Делайте 5–15 минут и обновляйте через refresh.
    • Хранение JWT в localStorage. Любая XSS превращается в кражу токена. Используйте HttpOnly-куки или память процесса.
    • Отсутствие CSRF-защиты для куки-сессий. SameSite=Lax помогает, но для критичных операций добавляйте CSRF-токен.
    • Доверие данным из JWT без проверки подписи. jwt.decode не проверяет подпись — всегда вызывайте jwt.verify.
    • Реализация OAuth2 вручную. Протокол кажется простым, но детали PKCE, state, nonce легко упустить. Берите проверенные библиотеки.
    • Смешение ролей в access-токене без актуализации. Если права пользователя поменялись, старый JWT всё ещё их содержит до истечения срока.

    Заключение

    Сессии, JWT и OAuth2 — не конкуренты, а инструменты с разными зонами ответственности. Для классического веб-приложения с серверным рендерингом сессии в Redis остаются самым простым и безопасным выбором. JWT раскрывают потенциал в распределённых API и мобильных клиентах, особенно в паре с refresh-токенами. OAuth2 нужен там, где требуется делегированный доступ или социальный вход.

    Выбирайте подход осознанно, опираясь на модель угроз и эксплуатационные требования, и не пренебрегайте базовыми мерами: HTTPS, HttpOnly-куки, короткие TTL, проверка подписи и валидация всех входных параметров.

    Иконка глаза1 186

    Комментарии

    0

    Постройте личный план изучения Основы Git до уровня Middle — бесплатно!

    Основы Git — часть карты развития Frontend, Backend, DevOps

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

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

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

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

    HTML и CSS

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

    CSS Flexbox

    Антон Ларичев
    Гарантия
    Бонусы
    иконка звёздочки рейтинга4.9
    бесплатно
    Подробнее
    изображение курса

    Основы JavaScript

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

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

    Картинка поста Qwen 3.8 Max для кода: как подключить из России
    Иконка аватараАнтон
    Иконка календаря24 октября 2026
    AI-инструментыapiразработкаjuniorИконка уровня junior

    Qwen 3.8 Max для кода: как подключить из России

    Qwen 3.8 Max — флагманская модель Alibaba с контекстом в 1 млн токенов и ответом до 131 тыс. токенов, которую Alibaba позиционирует прежде всего для программирования. Работать с ней из России проще всего в Qwen Code или OpenCode через ключ AI для кода от PurpleSchool: оплата в рублях, без VPN и без аккаунта Alibaba Cloud. Модель подключается по протоколу OpenAI Responses API — ниже готовые конфиги для обоих клиентов, характеристики модели и частые ошибки.

    Иконка чипа0
    Иконка глаза42
    Иконка комментариев0
    Картинка поста Codex не работает: частые ошибки и решения
    Иконка аватараАнтон
    Иконка календаря23 октября 2026
    AI-инструментыapiразработкаjuniorИконка уровня junior

    Codex не работает: частые ошибки и решения

    Чаще всего Codex не работает по одной из четырёх причин: команда `codex` не находится в системе, Codex пытается войти в аккаунт OpenAI, который из России недоступен, неправильно настроен провайдер в `~/.codex/config.toml` или песочница не даёт командам выйти в сеть. Ниже — ошибки по симптомам: что вы видите, почему это происходит и что исправить. В конце — как включить подробный лог, если ни один пункт не подошёл.

    Иконка чипа0
    Иконка глаза106
    Иконка комментариев0
    Картинка поста Continue в VS Code с Claude из России: настройка
    Иконка аватараАнтон
    Иконка календаря22 октября 2026
    AI-инструментыAnthropicразработкаjuniorИконка уровня junior

    Continue в VS Code с Claude из России: настройка

    Continue — бесплатное расширение для VS Code с открытым кодом: чат по проекту, правки выделенного кода и агентный режим. Своей модели у него нет, модель подключается в файле `config.yaml`. Из России напрямую Claude в Continue не заработает: API Anthropic отклоняет запросы с российских адресов, а ключ Anthropic оплачивается зарубежной картой. Решение — указать в конфиге провайдера `anthropic` свой адрес API (`apiBase`) и ключ AI для кода от PurpleSchool с оплатой в рублях. Ниже — установка, готовый `config.yaml`, проверка и частые ошибки.

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