Введение: почему 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