Введение
Каждый API должен знать, кто отправляет запрос. Без аутентификации API открыт для всех — любой может читать данные, создавать ресурсы, удалять записи. Но какой метод выбрать?
API Key, Basic Auth, JWT, OAuth 2.0, HMAC — каждый решает проблему по-своему, с разным уровнем безопасности, сложности и удобства. В этой статье — честное сравнение всех методов: как работают, когда использовать и как реализовать.
Аутентификация ≠ Авторизация
- Аутентификация (authentication) — «кто вы?» Проверка личности.
- Авторизация (authorization) — «что вам можно?» Проверка прав доступа.
Сначала аутентификация, потом авторизация. Эта статья — про аутентификацию.
📋 Содержание
1. API Key
Как работает
Сервер выдаёт клиенту уникальную строку (ключ). Клиент передаёт её с каждым запросом. Сервер проверяет ключ в базе данных.
# В заголовке (рекомендуется)
curl https://api.example.com/data \
-H "X-API-Key: sk_live_abc123def456"
# В query-параметре (менее безопасно)
curl "https://api.example.com/data?api_key=sk_live_abc123def456"
Плюсы
- Максимально простая реализация
- Легко понять и использовать
- Подходит для server-to-server
- Легко ротировать
Минусы
- Нет срока действия (пока не отзовут)
- Один ключ = все разрешения
- Опасно хранить на клиенте
- Нет информации о пользователе
Реализация (Node.js)
const express = require('express');
const app = express();
function apiKeyAuth(req, res, next) {
const key = req.headers['x-api-key'] || req.query.api_key;
if (!key) {
return res.status(401).json({ error: 'API key required' });
}
// Проверка в БД (используйте хеш, не храните ключи в открытом виде!)
const client = await db.clients.findOne({
where: { api_key_hash: crypto.createHash('sha256').update(key).digest('hex') }
});
if (!client) {
return res.status(401).json({ error: 'Invalid API key' });
}
req.client = client;
next();
}
app.use('/api', apiKeyAuth);
Кто использует: Google Maps, OpenWeatherMap, Stripe (для серверных запросов), SendGrid
2. Basic Auth
Как работает
Клиент передаёт username:password в Base64-кодировке через заголовок Authorization:
# curl с Basic Auth
curl -u admin:secret123 https://api.example.com/users
# Эквивалент:
# Authorization: Basic YWRtaW46c2VjcmV0MTIz
# (base64 от "admin:secret123")
Base64 — это НЕ шифрование
Base64 легко декодируется. echo "YWRtaW46c2VjcmV0MTIz" | base64 -d → admin:secret123. Без HTTPS логин и пароль передаются фактически в открытом виде.
Плюсы
- Встроен в HTTP-стандарт
- Поддержка во всех HTTP-клиентах
- Простейшая реализация
Минусы
- Пароль отправляется каждый запрос
- Нет срока действия
- Опасен без HTTPS
- Нет механизма отзыва
Когда использовать: внутренние сервисы, CI/CD, быстрые прототипы. Всегда через HTTPS.
3. Bearer Token
Как работает
Клиент получает токен (обычно после логина) и передаёт его в заголовке Authorization: Bearer <token>:
{email, password}
и выдаёт токен
токен
Authorization: Bearer ...
# 1. Логин — получаем токен
curl -X POST https://api.example.com/auth/login \
-H "Content-Type: application/json" \
-d '{"email": "ivan@test.ru", "password": "secret"}'
# {"token": "abc123xyz...", "expires_in": 3600}
# 2. Используем токен
curl https://api.example.com/me \
-H "Authorization: Bearer abc123xyz..."
Bearer Token — это формат передачи, а не конкретная технология. Токеном может быть случайная строка, JWT или opaque-токен.
Кто использует: практически все современные API
4. JWT (JSON Web Token)
Как работает
JWT — это Bearer Token, который содержит данные внутри себя. Три части, разделённые точками:
eyJhbGciOiJIUzI1NiJ9.eyJ1c2VyX2lkIjo0Miwicm9sZSI6ImFkbWluIiwiZXhwIjoxNzA4NzAwMDAwfQ.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c
↑ Header (alg, typ) ↑ Payload (данные) ↑ Signature (подпись)
// Payload (декодированный)
{
"user_id": 42,
"role": "admin",
"email": "ivan@test.ru",
"iat": 1708600000,
"exp": 1708700000
}
Плюсы
- Stateless — сервер не хранит сессии
- Масштабируемость (нет общего хранилища)
- Данные внутри токена (не нужен запрос в БД)
- Кросс-доменная работа
- Стандарт RFC 7519
Минусы
- Нельзя отозвать до истечения
- Payload видны всем (Base64)
- Больший размер (~500-1000 байт)
- Уязвимость при неправильном алгоритме
Реализация (Node.js)
const jwt = require('jsonwebtoken');
const SECRET = process.env.JWT_SECRET;
// Создание токена
app.post('/auth/login', async (req, res) => {
const user = await validateCredentials(req.body);
if (!user) return res.status(401).json({ error: 'Invalid credentials' });
const token = jwt.sign(
{ user_id: user.id, role: user.role, email: user.email },
SECRET,
{ expiresIn: '1h' }
);
const refreshToken = jwt.sign(
{ user_id: user.id, type: 'refresh' },
SECRET,
{ expiresIn: '30d' }
);
res.json({ token, refresh_token: refreshToken, expires_in: 3600 });
});
// Проверка токена (middleware)
function jwtAuth(req, res, next) {
const auth = req.headers.authorization;
if (!auth?.startsWith('Bearer ')) {
return res.status(401).json({ error: 'Bearer token required' });
}
try {
const payload = jwt.verify(auth.slice(7), SECRET);
req.user = payload;
next();
} catch (err) {
if (err.name === 'TokenExpiredError') {
return res.status(401).json({ error: 'Token expired' });
}
return res.status(401).json({ error: 'Invalid token' });
}
}
Реализация (Python / FastAPI)
import jwt
from datetime import datetime, timedelta
from fastapi import Depends, HTTPException, Header
SECRET = os.environ["JWT_SECRET"]
ALGORITHM = "HS256"
def create_token(user_id: int, role: str) -> str:
payload = {
"user_id": user_id,
"role": role,
"exp": datetime.utcnow() + timedelta(hours=1),
"iat": datetime.utcnow(),
}
return jwt.encode(payload, SECRET, algorithm=ALGORITHM)
async def jwt_auth(authorization: str = Header(...)):
if not authorization.startswith("Bearer "):
raise HTTPException(401, "Bearer token required")
token = authorization[7:]
try:
payload = jwt.decode(token, SECRET, algorithms=[ALGORITHM])
return payload
except jwt.ExpiredSignatureError:
raise HTTPException(401, "Token expired")
except jwt.InvalidTokenError:
raise HTTPException(401, "Invalid token")
@app.get("/api/me")
async def get_me(user=Depends(jwt_auth)):
return {"user_id": user["user_id"], "role": user["role"]}
⚠️ JWT: Refresh Token Pattern
Access Token — короткоживущий (15 мин — 1 час). Refresh Token — долгоживущий (30 дней), хранится безопасно, используется для получения нового Access Token. Это стандартная практика.
5. OAuth 2.0
Как работает
OAuth 2.0 — это протокол делегированной авторизации. Позволяет приложению получить доступ к ресурсам пользователя без передачи его пароля.
Authorization Code Flow (самый распространённый)
нажимает
«Login with Google»
Google OAuth
разрешает доступ
с code
code на token
# Шаг 1: Редирект пользователя на Google
# https://accounts.google.com/o/oauth2/v2/auth?
# client_id=YOUR_CLIENT_ID&
# redirect_uri=https://yourapp.com/callback&
# response_type=code&
# scope=openid email profile&
# state=random_csrf_token
# Шаг 2: Google редиректит назад с code
# https://yourapp.com/callback?code=AUTH_CODE&state=random_csrf_token
# Шаг 3: Сервер обменивает code на token
curl -X POST https://oauth2.googleapis.com/token \
-H "Content-Type: application/x-www-form-urlencoded" \
-d "code=AUTH_CODE" \
-d "client_id=YOUR_CLIENT_ID" \
-d "client_secret=YOUR_CLIENT_SECRET" \
-d "redirect_uri=https://yourapp.com/callback" \
-d "grant_type=authorization_code"
# Ответ:
# {"access_token": "ya29.xxx", "token_type": "Bearer", "expires_in": 3600}
Grant Types (потоки авторизации)
| Grant Type | Сценарий | Безопасность |
|---|---|---|
| Authorization Code | Веб-приложения с бэкендом | Высокая |
| Authorization Code + PKCE | SPA, мобильные приложения | Высокая |
| Client Credentials | Server-to-server (M2M) | Высокая |
| Device Code | Smart TV, IoT | Средняя |
| Низкая (deprecated) |
Плюсы
- Делегированный доступ (без передачи пароля)
- Scopes — гранулярные разрешения
- Стандарт индустрии
- Поддержка SSO
Минусы
- Сложная реализация
- Много разных Grant Types
- Требует правильной настройки
- Overkill для простых API
Кто использует: Google, Facebook, GitHub, Twitter, Microsoft — все крупные платформы
6. HMAC (подпись запроса)
Как работает
Клиент подписывает каждый запрос секретным ключом. Сервер пересчитывает подпись и сравнивает. Защищает от подделки и replay-атак.
const crypto = require('crypto');
function signRequest(method, path, body, secret) {
const timestamp = Math.floor(Date.now() / 1000).toString();
const message = `${timestamp}.${method}.${path}.${body || ''}`;
const signature = crypto
.createHmac('sha256', secret)
.update(message)
.digest('hex');
return { signature, timestamp };
}
// Отправка
const { signature, timestamp } = signRequest(
'POST', '/api/payments', '{"amount":100}', SECRET_KEY
);
// curl -X POST https://api.example.com/api/payments \
// -H "X-Signature: sha256=abc123..." \
// -H "X-Timestamp: 1708600000" \
// -H "Content-Type: application/json" \
// -d '{"amount":100}'
# Проверка подписи (сервер)
import hmac
import hashlib
import time
def verify_hmac(request):
signature = request.headers.get('X-Signature', '').replace('sha256=', '')
timestamp = request.headers.get('X-Timestamp', '')
# Защита от replay-атак: запрос не старше 5 минут
if abs(time.time() - int(timestamp)) > 300:
return False
message = f"{timestamp}.{request.method}.{request.path}.{request.body}"
expected = hmac.new(
SECRET_KEY.encode(), message.encode(), hashlib.sha256
).hexdigest()
return hmac.compare_digest(signature, expected)
Кто использует: AWS (Signature V4), Stripe (webhook signatures), Twilio, GitHub Webhooks
Сравнительная таблица
| Метод | Сложность | Безопасность | Stateless | Лучший сценарий |
|---|---|---|---|---|
| API Key | Простой | Средняя | Да | Публичные API, server-to-server |
| Basic Auth | Простой | Низкая | Да | Внутренние сервисы, CI/CD |
| Bearer Token | Средний | Высокая | Зависит | Универсальный формат |
| JWT | Средний | Высокая | Да | SPA, мобильные, микросервисы |
| OAuth 2.0 | Сложный | Очень высокая | Зависит | Login with ..., делегированный доступ |
| HMAC | Сложный | Очень высокая | Да | Платёжные API, вебхуки |
Как выбрать
Дерево решений
- Публичный API для разработчиков? → API Key
- SPA / мобильное приложение с пользователями? → JWT (Bearer Token)
- «Login with Google/GitHub»? → OAuth 2.0 (Authorization Code + PKCE)
- Server-to-server (микросервисы)? → OAuth 2.0 Client Credentials или API Key
- Вебхуки? → HMAC-подпись
- Внутренний сервис / быстрый прототип? → Basic Auth (через HTTPS)
- Платёжный API? → API Key + HMAC + Idempotency-Key
Best Practices
1. Всегда HTTPS
Без HTTPS любой метод аутентификации уязвим — токены, ключи и пароли передаются в открытом виде. Исключений нет.
2. Храните секреты правильно
- Сервер: переменные окружения, Vault, AWS Secrets Manager
- SPA: JWT в httpOnly cookie (не в localStorage!)
- Мобильные: Keychain (iOS) / Keystore (Android)
- Git: никогда не коммитьте токены. Используйте
.env+.gitignore
3. Ротация и отзыв
- API Key — реализуйте endpoint для ротации
- JWT — короткий
exp(15 мин) + Refresh Token - OAuth — используйте
token_revocationendpoint
4. Rate Limiting по ключу/токену
Ограничивайте количество запросов на API Key / пользователя. Возвращайте 429 Too Many Requests с заголовками X-RateLimit-*.
5. Логирование
Логируйте: кто, когда, откуда. Не логируйте: сами токены и пароли. Полезно для отладки и аудита безопасности.
FAQ
❓ Чем отличается аутентификация от авторизации?
Ответ: Аутентификация — «кто вы?» (токен, ключ, пароль). Авторизация — «что вам можно?» (роли, scopes). Сначала аутентификация, затем авторизация. API Key — только аутентификация. OAuth 2.0 — и то, и другое (через scopes).
❓ Какой метод аутентификации API выбрать?
Ответ: API Key — для серверных интеграций. JWT — для SPA/мобильных. OAuth 2.0 — для «Login with ...». Basic Auth — только внутренние сервисы через HTTPS. HMAC — для вебхуков и платёжных API.
❓ Безопасно ли передавать API Key в URL?
Ответ: Нет. URL попадает в логи, историю браузера, Referer. Передавайте API Key через заголовок X-API-Key или Authorization.
❓ Чем JWT лучше сессий для API?
Ответ: JWT — stateless (не нужно общее хранилище сессий), масштабируемость, кросс-доменная работа. Минусы: нельзя отозвать до истечения, больший размер. Сессии лучше для монолитов с мгновенным отзывом доступа.
Заключение
📝 Ключевые выводы
- API Key — просто, хорошо для серверных интеграций. Храните в заголовке, не в URL.
- JWT — stateless, идеален для SPA и микросервисов. Короткий exp + Refresh Token.
- OAuth 2.0 — стандарт для делегированного доступа. Используйте Authorization Code + PKCE.
- HMAC — максимальная защита для платёжных API и вебхуков.
- Basic Auth — только для внутренних сервисов через HTTPS.
- HTTPS обязателен для всех методов без исключений.
Выбор метода аутентификации — это баланс между безопасностью и удобством. Используйте простейший метод, который обеспечивает нужный уровень защиты. Не усложняйте без необходимости, но и не экономьте на безопасности.
🎯 Тестируйте аутентификацию API
LightBox API — создавайте моковые эндпоинты с любым типом аутентификации для тестирования фронтенда и интеграций.
- ✓ API Key, Bearer Token аутентификация
- ✓ Настраиваемые HTTP-статусы (401, 403)
- ✓ Swagger документация
- ✓ Логирование запросов
- ✓ Бесплатный план
Статья опубликована: 23 февраля 2026
Автор: LightBox API Team