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

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

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

Начать курс

Введение в OAuth 2.0 и JWT на PHP

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

Вы узнаете, как настроить сервер авторизации, выпускать и проверять JWT токены, организовать выдачу refresh-токенов и защитить свои API-эндпоинты. Все примеры кода готовы к использованию в ваших проектах.

Основы протокола OAuth 2.0

OAuth 2.0 — это протокол авторизации, который позволяет приложениям получать ограниченный доступ к ресурсам пользователя без передачи его учётных данных. В контексте PHP-приложения OAuth 2.0 обычно реализуется через грант авторизационного кода (Authorization Code Grant) или грант пароля (Password Grant) для собственных сервисов.

Ключевые роли в OAuth 2.0

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

Поток получения токена через Authorization Code Grant

  1. Пользователь переходит на страницу авторизации
  2. После входа пользователь перенаправляется обратно в приложение с временным кодом
  3. PHP-сервер обменивает код на access_token и refresh_token
  4. Все последующие запросы к API выполняются с заголовком Authorization: Bearer <access_token>

Реализация JWT на PHP с библиотекой firebase/php-jwt

Для работы с JWT в PHP мы будем использовать популярную библиотеку firebase/php-jwt. Установим её через Composer:

composer require firebase/php-jwt

Генерация JWT токена

Создадим функцию для выпуска access-токена с полезной нагрузкой (claims):

<?php
use Firebase\JWT\JWT;
use Firebase\JWT\Key;

function generateAccessToken(int $userId, string $email): string {
    $secretKey = 'your-256-bit-secret-key-here';
    $issuedAt = time();
    $expirationTime = $issuedAt + 3600; // 1 час

    $payload = [
        'iss' => 'pythonlib.ru',
        'iat' => $issuedAt,
        'exp' => $expirationTime,
        'sub' => $userId,
        'email' => $email,
        'roles' => ['user']
    ];

    return JWT::encode($payload, $secretKey, 'HS256');
}

Верификация JWT токена

Проверка подлинности токена при каждом запросе к защищённому ресурсу:

<?php
function validateAccessToken(string $token): ?object {
    $secretKey = 'your-256-bit-secret-key-here';
    try {
        $decoded = JWT::decode($token, new Key($secretKey, 'HS256'));
        return $decoded;
    } catch (\Exception $e) {
        // Токен истёк, недействителен или подпись не совпадает
        return null;
    }
}

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

Пример простого middleware, который можно использовать с любым фреймворком:

<?php
function authMiddleware(): ?object {
    $headers = getallheaders();
    $authHeader = $headers['Authorization'] ?? '';

    if (!preg_match('/Bearer\s(\S+)/', $authHeader, $matches)) {
        http_response_code(401);
        echo json_encode(['error' => 'Токен не предоставлен']);
        exit;
    }

    $token = $matches[1];
    $user = validateAccessToken($token);

    if (!$user) {
        http_response_code(401);
        echo json_encode(['error' => 'Токен недействителен или истёк']);
        exit;
    }

    return $user;
}

// Использование в эндпоинте:
// $currentUser = authMiddleware();
// Теперь $currentUser содержит данные пользователя из токена

Реализация полного OAuth 2.0 сервера на PHP

Теперь объединим OAuth 2.0 и JWT в полноценный сервер авторизации. Мы реализуем грант пароля (password grant), который подходит для доверенных клиентов (например, ваше мобильное приложение или SPA).

Эндпоинт для получения токена

<?php
// /token.php
require_once 'vendor/autoload.php';

function handleTokenRequest(): void {
    $grantType = $_POST['grant_type'] ?? '';
    $clientId = $_POST['client_id'] ?? '';
    $clientSecret = $_POST['client_secret'] ?? '';
    
    // Проверка клиента (в реальном проекте — из БД)
    if ($clientId !== 'my_app' || $clientSecret !== 'my_secret') {
        http_response_code(401);
        echo json_encode(['error' => 'invalid_client']);
        return;
    }

    if ($grantType === 'password') {
        $username = $_POST['username'] ?? '';
        $password = $_POST['password'] ?? '';

        // Проверка учётных данных (в реальном проекте — через password_verify)
        if ($username === 'user@example.com' && $password === 'password123') {
            $userId = 1;
            $accessToken = generateAccessToken($userId, $username);
            $refreshToken = bin2hex(random_bytes(32)); // Простой refresh токен

            // Сохраняем refresh токен в БД
            // saveRefreshToken($userId, $refreshToken);

            echo json_encode([
                'access_token' => $accessToken,
                'token_type' => 'Bearer',
                'expires_in' => 3600,
                'refresh_token' => $refreshToken
            ]);
        } else {
            http_response_code(401);
            echo json_encode(['error' => 'invalid_grant']);
        }
    }
}

handleTokenRequest();

Обновление access-токена через refresh_token

<?php
// /refresh.php
function handleRefreshRequest(): void {
    $refreshToken = $_POST['refresh_token'] ?? '';

    // Проверяем refresh токен в БД
    // $storedToken = getRefreshTokenFromDB($refresh                

Блоги

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