OAuth 2.0 и JWT авторизация на JavaScript: полное руководство для начинающих

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

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

Начать курс

Введение: почему OAuth 2.0 и JWT — стандарт современной авторизации

В современной веб-разработке безопасная аутентификация и авторизация пользователей — одна из ключевых задач. Два наиболее популярных протокола и формата, которые решают эту задачу — OAuth 2.0 и JWT (JSON Web Token). Несмотря на то, что они часто используются вместе, это разные вещи: OAuth 2.0 — это протокол делегирования доступа, а JWT — формат токена.

В этой статье мы разберем, как работает OAuth 2.0, что такое JWT, и как реализовать их на JavaScript (Node.js). Материал ориентирован на начинающих разработчиков, поэтому мы будем двигаться от теории к практике с понятными примерами кода.

Что такое OAuth 2.0 и как он работает

OAuth 2.0 (Open Authorization) — это протокол, который позволяет приложению получить ограниченный доступ к ресурсам пользователя без передачи его логина и пароля. Представьте, что вы хотите войти на сайт через Google или GitHub — это и есть OAuth 2.0.

Основные роли в OAuth 2.0

  • Resource Owner — пользователь, владеющий данными
  • Client — приложение, которое запрашивает доступ
  • Authorization Server — сервер, выдающий токены (например, Google)
  • Resource Server — сервер, хранящий данные пользователя

Поток Authorization Code Grant (на примере Node.js)

Самый распространенный и безопасный поток OAuth 2.0 — Authorization Code Grant. Рассмотрим его реализацию с использованием Express.js.

// Установка зависимостей
// npm install express axios dotenv

// .env
CLIENT_ID=your_client_id
CLIENT_SECRET=your_client_secret
REDIRECT_URI=http://localhost:3000/callback
const express = require('express');
const axios = require('axios');
require('dotenv').config();

const app = express();

// Шаг 1: Перенаправление пользователя на страницу авторизации
app.get('/auth', (req, res) => {
    const authUrl = `https://provider.com/oauth/authorize?client_id=${process.env.CLIENT_ID}&redirect_uri=${process.env.REDIRECT_URI}&response_type=code&scope=email`;
    res.redirect(authUrl);
});

// Шаг 2: Обработка callback с authorization code
app.get('/callback', async (req, res) => {
    const { code } = req.query;

    try {
        // Обмен authorization code на access token
        const tokenResponse = await axios.post('https://provider.com/oauth/token', {
            client_id: process.env.CLIENT_ID,
            client_secret: process.env.CLIENT_SECRET,
            code,
            redirect_uri: process.env.REDIRECT_URI,
            grant_type: 'authorization_code'
        });

        const { access_token, refresh_token } = tokenResponse.data;
        
        // Сохраняем токены (в реальном проекте - в БД)
        req.session.accessToken = access_token;
        req.session.refreshToken = refresh_token;

        res.send('Авторизация успешна!');
    } catch (error) {
        res.status(500).send('Ошибка авторизации');
    }
});

app.listen(3000, () => console.log('Сервер запущен на порту 3000'));

JWT (JSON Web Token): структура и создание

JWT — это компактный и самодостаточный способ передачи информации между сторонами в виде JSON-объекта. Токен состоит из трех частей, разделенных точками:

  • Header — тип токена и алгоритм подписи (например, HS256)
  • Payload — данные (claims), которые мы хотим передать
  • Signature — подпись, обеспечивающая целостность данных

Создание JWT на Node.js

Для работы с JWT мы будем использовать библиотеку jsonwebtoken.

// npm install jsonwebtoken

const jwt = require('jsonwebtoken');

const secretKey = 'ваш_секретный_ключ_минимум_32_символа';

// Создание токена
function generateToken(user) {
    const payload = {
        userId: user.id,
        email: user.email,
        role: user.role
    };

    const options = {
        expiresIn: '1h' // токен действует 1 час
    };

    return jwt.sign(payload, secretKey, options);
}

// Проверка токена
function verifyToken(token) {
    try {
        const decoded = jwt.verify(token, secretKey);
        return { valid: true, data: decoded };
    } catch (error) {
        if (error.name === 'TokenExpiredError') {
            return { valid: false, error: 'Токен истек' };
        }
        return { valid: false, error: 'Невалидный токен' };
    }
}

// Пример использования
const user = { id: 1, email: 'user@example.com', role: 'user' };
const token = generateToken(user);
console.log('Сгенерированный токен:', token);

const verification = verifyToken(token);
console.log('Результат проверки:', verification);

Реализация JWT авторизации в Express.js

Теперь объединим OAuth 2.0 и JWT в полноценную систему авторизации. После получения access token от провайдера, мы создадим свой JWT для внутреннего использования.

Middleware для проверки JWT

// middleware/auth.js
const jwt = require('jsonwebtoken');

function authMiddleware(req, res, next) {
    const authHeader = req.headers['authorization'];
    
    if (!authHeader) {
        return res.status(401).json({ error: 'Требуется авторизация' });
    }

    // Bearer token
    const token = authHeader.split(' ')[1];
    
    if (!token) {
        return res.status(401).json({ error: 'Неверный формат токена' });
    }

    try {
        const decoded = jwt.verify(token, process.env.JWT_SECRET);
        req.user = decoded;
        next();
    } catch (error) {
        if (error.name === 'TokenExpiredError') {
            return res.status(401).json({ error: 'Токен истек' });
        }
        return res.status(403).json({ error: 'Недействительный токен' });
    }
}

module.exports = authMiddleware;

Защищенные маршруты

const express = require('express');
const authMiddleware = require('./middleware/auth');

const app = express();

// Публичный маршрут
app.get('/public', (req, res) => {
    res.json({ message: 'Этот маршрут доступен всем' });
});

// Защищенный маршрут
app.get('/profile', authMiddleware, (req, res) => {
    res.json({
        message: 'Доступ разрешен',
        user: req.user
    });
});

// Маршрут только для администраторов
app.get                

Блоги

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