JWT токены в PHP: Полное руководство по реализации
JWT (JSON Web Token) — это открытый стандарт (RFC 7519) для создания токенов доступа, основанных на JSON-формате. В PHP JWT широко используется для реализации бесстатусной аутентификации (stateless authentication) в REST API, одностраничных приложениях (SPA) и микросервисах.
В этой статье мы подробно разберём, как работать с JWT токенами в PHP: от установки библиотеки до создания, проверки и обновления токенов.
Что такое JWT и зачем он нужен?
JWT состоит из трёх частей, разделённых точками:
- Header (заголовок) — содержит тип токена (JWT) и алгоритм подписи (например, HS256 или RS256).
- Payload (полезная нагрузка) — содержит утверждения (claims): идентификатор пользователя, роль, время выпуска (iat), срок действия (exp) и другие данные.
- Signature (подпись) — создаётся путём хеширования заголовка и полезной нагрузки с использованием секретного ключа.
Основные преимущества JWT:
- Не требует хранения сессий на сервере (stateless).
- Может содержать любые данные (например, роль пользователя).
- Работает с разными доменами и мобильными приложениями.
- Легко проверяется без обращения к базе данных.
Установка библиотеки firebase/php-jwt
Для работы с JWT в PHP мы будем использовать популярную библиотеку firebase/php-jwt. Установка выполняется через Composer:
composer require firebase/php-jwt
После установки в проекте появится автозагрузка Composer, которую нужно подключить:
require_once 'vendor/autoload.php';
use Firebase\JWT\JWT;
use Firebase\JWT\Key;
Создание JWT токена
Для создания токена нужно определить секретный ключ ($secretKey) и сформировать payload. Пример:
use Firebase\JWT\JWT;
$secretKey = 'your-256-bit-secret-key-here';
$issuedAt = time();
$expirationTime = $issuedAt + 3600; // токен живёт 1 час
$payload = [
'iss' => 'pythonlib.ru', // издатель
'iat' => $issuedAt, // время выпуска
'exp' => $expirationTime, // срок действия
'sub' => 123, // идентификатор пользователя
'role' => 'admin' // кастомные данные
];
$jwt = JWT::encode($payload, $secretKey, 'HS256');
echo $jwt;
В результате получится строка вида: eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJpc3MiOiJweXRob25saWIucnUiLCJpYXQiOjE3Mjg0MDAwMDAsImV4cCI6MTcyODQwMzYwMCwic3ViIjoxMjMsInJvbGUiOiJhZG1pbiJ9.signature
Проверка и декодирование JWT
При получении токена от клиента (например, из заголовка Authorization: Bearer <token>) его нужно проверить:
use Firebase\JWT\JWT;
use Firebase\JWT\Key;
$secretKey = 'your-256-bit-secret-key-here';
$jwt = $_SERVER['HTTP_AUTHORIZATION'] ?? '';
try {
$decoded = JWT::decode($jwt, new Key($secretKey, 'HS256'));
$userId = $decoded->sub;
$role = $decoded->role;
echo "Пользователь #{$userId} с ролью {$role} авторизован.";
} catch (\Exception $e) {
http_response_code(401);
echo "Ошибка: " . $e->getMessage();
}
Важно: библиотека автоматически проверяет срок действия токена (exp) и время выпуска (iat). Если токен истёк или недействителен, будет выброшено исключение.
Обновление JWT (Refresh Token)
Для повышения безопасности JWT обычно делают короткоживущими (15–60 минут). Для долгой сессии используют Refresh Token — отдельный токен, который хранится в базе данных и позволяет получить новый Access Token без повторного ввода логина/пароля.
Пример реализации refresh:
function refreshAccessToken(string $refreshToken, string $secretKey): ?string {
// Проверяем refresh token в базе данных (упрощённая логика)
$storedHash = 'hash_from_database'; // должен быть получен из БД
if (!password_verify($refreshToken, $storedHash)) {