Идёт обновление сайта. Несколько дней возможны сбои в оформлении и переводах. Документация работает — если страница выглядит сломанной, обновите её позже.

Документация
L Laravel L intervention/image
Войти
Главная Laravel 10.x Laravel Passport

Laravel Passport

10.x 7 мар 2026 г.

#Введение

Laravel Passport предоставляет полноценную реализацию сервера OAuth2 для вашего Laravel-приложения за считанные минуты. Passport построен на базе League OAuth2 server, поддерживаемого Энди Миллингтоном и Саймоном Хампом.

Внимание

В этой документации предполагается, что вы уже знакомы с OAuth2. Если вы ничего не знаете об OAuth2, рекомендуется сначала ознакомиться с общей терминологией и особенностями OAuth2, прежде чем продолжать.

#Passport или Sanctum?

Прежде чем начать, стоит определить, что лучше подходит для вашего приложения — Laravel Passport или Laravel Sanctum. Если вашему приложению обязательно нужна поддержка OAuth2, следует использовать Laravel Passport.

Однако, если вы пытаетесь аутентифицировать одностраничное приложение, мобильное приложение или выдавать API-токены, лучше использовать Laravel Sanctum. Laravel Sanctum не поддерживает OAuth2, но обеспечивает гораздо более простой опыт разработки аутентификации API.

#Установка

Для начала установите Passport через менеджер пакетов Composer:

composer require laravel/passport

Service provider Passport регистрирует собственную директорию миграций базы данных, поэтому после установки пакета следует выполнить миграции. Миграции Passport создадут таблицы, необходимые вашему приложению для хранения OAuth2 клиентов и токенов доступа:

php artisan migrate

Далее выполните Artisan-команду passport:install. Эта команда создаст ключи шифрования, необходимые для генерации безопасных токенов доступа. Кроме того, команда создаст клиентов "personal access" и "password grant", которые будут использоваться для генерации токенов доступа:

php artisan passport:install
Примечание

Если вы хотите использовать UUID в качестве первичного ключа модели Passport Client вместо автоинкрементных целых чисел, установите Passport с использованием опции uuids.

После выполнения команды passport:install добавьте трейт Laravel\Passport\HasApiTokens в модель App\Models\User. Этот трейт добавит несколько вспомогательных методов, позволяющих проверять токен и области аутентифицированного пользователя. Если ваша модель уже использует трейт Laravel\Sanctum\HasApiTokens, его можно удалить:

<?php

namespace App\Models;

use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Foundation\Auth\User as Authenticatable;
use Illuminate\Notifications\Notifiable;
use Laravel\Passport\HasApiTokens;

class User extends Authenticatable
{
    use HasApiTokens, HasFactory, Notifiable;
}

Наконец, в конфигурационном файле вашего приложения config/auth.php определите охрану api и установите для параметра driver значение passport. Это укажет приложению использовать TokenGuard Passport при аутентификации входящих API-запросов:

'guards' => [
    'web' => [
        'driver' => 'session',
        'provider' => 'users',
    ],

    'api' => [
        'driver' => 'passport',
        'provider' => 'users',
    ],
],

#UUID клиентов

Вы также можете запустить команду passport:install с опцией --uuids. Эта опция сообщит Passport, что вы хотите использовать UUIDs вместо целых чисел с автоинкрементом в качестве значений первичных ключей модели Passport Client. После запуска passport:install с опцией --uuids вы получите дополнительные инструкции по отключению стандартных миграций Passport:

php artisan passport:install --uuids

#Развёртывание Passport

При первом развёртывании Passport на серверах вашего приложения, скорее всего, потребуется выполнить команду passport:keys. Эта команда генерирует ключи шифрования, необходимые Passport для создания токенов доступа. Сгенерированные ключи обычно не хранятся в системе контроля версий:

php artisan passport:keys

При необходимости вы можете указать путь, откуда должны загружаться ключи Passport. Для этого используйте метод Passport::loadKeysFrom. Обычно этот метод вызывается в методе boot класса App\Providers\AuthServiceProvider вашего приложения:

/**
 * Регистрация сервисов аутентификации / авторизации.
 */
public function boot(): void
{
    Passport::loadKeysFrom(__DIR__.'/../secrets/oauth');
}

#Загрузка ключей из окружения

В качестве альтернативы вы можете опубликовать конфигурационный файл Passport с помощью команды vendor:publish Artisan:

php artisan vendor:publish --tag=passport-config

После публикации конфигурационного файла вы можете загрузить ключи шифрования вашего приложения, определив их в переменных окружения:

PASSPORT_PRIVATE_KEY="-----BEGIN RSA PRIVATE KEY-----
<private key here>
-----END RSA PRIVATE KEY-----"

PASSPORT_PUBLIC_KEY="-----BEGIN PUBLIC KEY-----
<public key here>
-----END PUBLIC KEY-----"

#Настройка миграций

Если вы не собираетесь использовать стандартные миграции Passport, вызовите метод Passport::ignoreMigrations в методе register класса App\Providers\AppServiceProvider. Стандартные миграции можно экспортировать с помощью команды vendor:publish Artisan:

php artisan vendor:publish --tag=passport-migrations

#Обновление Passport

При обновлении до новой мажорной версии Passport важно внимательно ознакомиться с руководством по обновлению.

#Конфигурация

#Хеширование секретов клиентов

Если вы хотите, чтобы секреты клиентов хранились в базе данных в виде хешей, вызовите метод Passport::hashClientSecrets в методе boot класса App\Providers\AuthServiceProvider вашего приложения:

use Laravel\Passport\Passport;

Passport::hashClientSecrets();

После включения этой опции все секреты клиентов будут доступны пользователю только сразу после создания. Поскольку значение секрета в открытом виде не хранится в базе, восстановить его в случае утери невозможно.

#Время жизни токенов

По умолчанию Passport выдаёт долгоживущие токены доступа с истечением через год. Если вы хотите настроить более длительное или короткое время жизни токенов, используйте методы tokensExpireIn, refreshTokensExpireIn и personalAccessTokensExpireIn. Эти методы следует вызывать в методе boot класса App\Providers\AuthServiceProvider вашего приложения:

/**
 * Регистрация сервисов аутентификации / авторизации.
 */
public function boot(): void
{
    Passport::tokensExpireIn(now()->addDays(15));
    Passport::refreshTokensExpireIn(now()->addDays(30));
    Passport::personalAccessTokensExpireIn(now()->addMonths(6));
}
Внимание

Столбцы expires_at в таблицах базы данных Passport доступны только для чтения и служат только для отображения. При выдаче токенов Passport хранит информацию о сроке действия внутри подписанных и зашифрованных токенов. Если необходимо аннулировать токен, следует отозвать его.

#Переопределение моделей по умолчанию

Вы можете расширять модели, используемые внутри Passport, определяя собственные модели, наследующие соответствующие модели Passport:

use Laravel\Passport\Client as PassportClient;

class Client extends PassportClient
{
    // ...
}

После определения своей модели вы можете указать Passport использовать её через класс Laravel\Passport\Passport. Обычно это делается в методе boot класса App\Providers\AuthServiceProvider вашего приложения:

use App\Models\Passport\AuthCode;
use App\Models\Passport\Client;
use App\Models\Passport\PersonalAccessClient;
use App\Models\Passport\RefreshToken;
use App\Models\Passport\Token;

/**
 * Регистрация сервисов аутентификации / авторизации.
 */
public function boot(): void
{
    Passport::useTokenModel(Token::class);
    Passport::useRefreshTokenModel(RefreshToken::class);
    Passport::useAuthCodeModel(AuthCode::class);
    Passport::useClientModel(Client::class);
    Passport::usePersonalAccessClientModel(PersonalAccessClient::class);
}

#Переопределение маршрутов

Иногда может потребоваться настроить маршруты, определённые Passport. Для этого сначала нужно игнорировать маршруты, регистрируемые Passport, добавив Passport::ignoreRoutes в метод register класса AppServiceProvider вашего приложения:

use Laravel\Passport\Passport;

/**
 * Регистрация сервисов приложения.
 */
public function register(): void
{
    Passport::ignoreRoutes();
}

Затем вы можете скопировать маршруты Passport из его файла маршрутов в файл routes/web.php вашего приложения и изменить их по своему усмотрению:

Route::group([
    'as' => 'passport.',
    'prefix' => config('passport.path', 'oauth'),
    'namespace' => '\Laravel\Passport\Http\Controllers',
], function () {
    // Маршруты Passport...
});

#Выдача токенов доступа

Использование OAuth2 через authorization codes — наиболее распространённый способ работы с OAuth2. При использовании authorization codes клиентское приложение перенаправляет пользователя на ваш сервер, где он может одобрить или отклонить запрос на выдачу токена доступа клиенту.

#Управление клиентами

Сначала разработчикам, создающим приложения, которые должны взаимодействовать с API вашего приложения, нужно зарегистрировать своё приложение, создав "клиента". Обычно это включает указание имени приложения и URL, на который ваше приложение будет перенаправлять после одобрения пользователем запроса на авторизацию.

#Команда passport:client

Самый простой способ создать клиента — использовать команду Artisan passport:client. Этой командой можно создать собственных клиентов для тестирования функционала OAuth2. При выполнении команды client Passport запросит у вас дополнительные сведения о клиенте и выдаст идентификатор клиента и секрет:

php artisan passport:client

URL-адреса перенаправления

Если вы хотите разрешить несколько URL перенаправления для клиента, укажите их через запятую при вводе URL в команде passport:client. Любые URL, содержащие запятые, должны быть URL-кодированы:

http://example.com/callback,http://examplefoo.com/callback

#JSON API

Поскольку пользователи вашего приложения не смогут использовать команду client, Passport предоставляет JSON API для создания клиентов. Это избавляет вас от необходимости вручную писать контроллеры для создания, обновления и удаления клиентов.

Однако вам нужно будет связать JSON API Passport с вашим собственным фронтендом, чтобы предоставить пользователям панель управления для управления клиентами. Ниже мы рассмотрим все конечные точки API для управления клиентами. Для удобства мы используем Axios для демонстрации HTTP-запросов к этим конечным точкам.

JSON API защищён middleware web и auth, поэтому его можно вызывать только из вашего приложения. Вызов из внешних источников невозможен.

#GET /oauth/clients

Этот маршрут возвращает всех клиентов аутентифицированного пользователя. Это полезно для отображения списка клиентов, чтобы пользователь мог их редактировать или удалять:

axios.get('/oauth/clients')
    .then(response => {
        console.log(response.data);
    });

#POST /oauth/clients

Этот маршрут используется для создания новых клиентов. Требуются два параметра: name клиента и URL redirect. URL redirect — это адрес, на который пользователь будет перенаправлен после одобрения или отклонения запроса на авторизацию.

При создании клиента ему присваиваются client ID и client secret. Эти значения используются при запросе токенов доступа к вашему приложению. Маршрут создания клиента возвращает новый экземпляр клиента:

const data = {
    name: 'Client Name',
    redirect: 'http://example.com/callback'
};

axios.post('/oauth/clients', data)
    .then(response => {
        console.log(response.data);
    })
    .catch (response => {
        // Вывести ошибки из ответа...
    });

#PUT /oauth/clients/{client-id}

Этот маршрут используется для обновления клиентов. Требуются два параметра: name клиента и URL redirect. URL redirect — это адрес, на который пользователь будет перенаправлен после одобрения или отклонения запроса на авторизацию. Маршрут возвращает обновлённый экземпляр клиента:

const data = {
    name: 'New Client Name',
    redirect: 'http://example.com/callback'
};

axios.put('/oauth/clients/' + clientId, data)
    .then(response => {
        console.log(response.data);
    })
    .catch (response => {
        // Вывести ошибки из ответа...
    });

#DELETE /oauth/clients/{client-id}

Этот маршрут используется для удаления клиентов:

axios.delete('/oauth/clients/' + clientId)
    .then(response => {
        // ...
    });

#Запрос токенов

#Перенаправление для авторизации

После создания клиента разработчики могут использовать client ID и секрет для запроса authorization code и токена доступа у вашего приложения. Сначала приложение должно сделать перенаправление на маршрут /oauth/authorize вашего приложения следующим образом:

use Illuminate\Http\Request;
use Illuminate\Support\Str;

Route::get('/redirect', function (Request $request) {
    $request->session()->put('state', $state = Str::random(40));

    $query = http_build_query([
        'client_id' => 'client-id',
        'redirect_uri' => 'http://third-party-app.com/callback',
        'response_type' => 'code',
        'scope' => '',
        'state' => $state,
        // 'prompt' => '', // "none", "consent", или "login"
    ]);

    return redirect('http://passport-app.test/oauth/authorize?'.$query);
});

Параметр prompt может использоваться для указания поведения аутентификации в приложении Passport.

Если значение prompt равно none, Passport всегда выдаст ошибку аутентификации, если пользователь ещё не аутентифицирован в приложении Passport. Если значение consent, Passport всегда покажет экран одобрения авторизации, даже если все области уже были предоставлены приложению. При значении login Passport всегда запросит повторный вход пользователя, даже если у него уже есть активная сессия.

Если параметр prompt не указан, пользователь будет запрошен об авторизации только в случае, если ранее он не предоставлял доступ приложению для запрашиваемых областей.

Примечание

Помните, что маршрут /oauth/authorize уже определён Passport. Вам не нужно определять этот маршрут вручную.

#Одобрение запроса

При получении запроса на авторизацию Passport автоматически реагирует в зависимости от параметра prompt (если он есть) и может показать пользователю шаблон с возможностью одобрить или отклонить запрос. Если пользователь одобряет запрос, он будет перенаправлен обратно на redirect_uri, указанный приложением. redirect_uri должен совпадать с URL redirect, указанным при создании клиента.

Если вы хотите настроить экран одобрения авторизации, вы можете опубликовать представления Passport с помощью команды vendor:publish Artisan. Опубликованные представления будут размещены в директории resources/views/vendor/passport:

php artisan vendor:publish --tag=passport-views

Иногда может потребоваться пропустить запрос авторизации, например, при авторизации клиента первого лица. Это можно сделать, расширив модель Client и определив метод skipsAuthorization. Если skipsAuthorization возвращает true, клиент будет одобрен, и пользователь сразу же будет перенаправлен на redirect_uri, если только приложение явно не указало параметр prompt при перенаправлении для авторизации:

<?php

namespace App\Models\Passport;

use Laravel\Passport\Client as BaseClient;

class Client extends BaseClient
{
    /**
     * Определяет, следует ли пропустить запрос авторизации для клиента.
     */
    public function skipsAuthorization(): bool
    {
        return $this->firstParty();
    }
}

#Обмен authorization code на токены доступа

Если пользователь одобрил запрос авторизации, он будет перенаправлен обратно в приложение. Клиент должен сначала проверить параметр state с сохранённым значением перед перенаправлением. Если параметр совпадает, клиент должен отправить POST-запрос вашему приложению для получения токена доступа. Запрос должен содержать authorization code, выданный вашим приложением при одобрении запроса:

use Illuminate\Http\Request;
use Illuminate\Support\Facades\Http;

Route::get('/callback', function (Request $request) {
    $state = $request->session()->pull('state');

    throw_unless(
        strlen($state) > 0 && $state === $request->state,
        InvalidArgumentException::class,
        'Неверное значение state.'
    );

    $response = Http::asForm()->post('http://passport-app.test/oauth/token', [
        'grant_type' => 'authorization_code',
        'client_id' => 'client-id',
        'client_secret' => 'client-secret',
        'redirect_uri' => 'http://third-party-app.com/callback',
        'code' => $request->code,
    ]);

    return $response->json();
});

Маршрут /oauth/token вернёт JSON-ответ с атрибутами access_token, refresh_token и expires_in. Атрибут expires_in содержит количество секунд до истечения срока действия токена доступа.

Примечание

Как и маршрут /oauth/authorize, маршрут /oauth/token уже определён Passport. Вам не нужно определять его вручную.

#JSON API

Passport также включает JSON API для управления авторизованными токенами доступа. Вы можете связать его с собственным фронтендом, чтобы предоставить пользователям панель управления токенами. Для удобства мы используем Axios для демонстрации HTTP-запросов к конечным точкам. JSON API защищён middleware web и auth, поэтому его можно вызывать только из вашего приложения.

#GET /oauth/tokens

Этот маршрут возвращает все авторизованные токены доступа, созданные аутентифицированным пользователем. Это полезно для отображения списка токенов, чтобы пользователь мог их отзывать:

axios.get('/oauth/tokens')
    .then(response => {
        console.log(response.data);
    });

#DELETE /oauth/tokens/{token-id}

Этот маршрут используется для отзыва авторизованных токенов доступа и связанных с ними refresh токенов:

axios.delete('/oauth/tokens/' + tokenId);

#Обновление токенов

Если ваше приложение выдаёт краткоживущие токены доступа, пользователям потребуется обновлять их с помощью refresh токена, выданного вместе с токеном доступа:

use Illuminate\Support\Facades\Http;

$response = Http::asForm()->post('http://passport-app.test/oauth/token', [
    'grant_type' => 'refresh_token',
    'refresh_token' => 'the-refresh-token',
    'client_id' => 'client-id',
    'client_secret' => 'client-secret',
    'scope' => '',
]);

return $response->json();

Маршрут /oauth/token вернёт JSON-ответ с атрибутами access_token, refresh_token и expires_in. Атрибут expires_in содержит количество секунд до истечения срока действия токена доступа.

#Отзыв токенов

Вы можете отозвать токен с помощью метода revokeAccessToken репозитория Laravel\Passport\TokenRepository. Для отзыва refresh токенов используйте метод revokeRefreshTokensByAccessTokenId репозитория Laravel\Passport\RefreshTokenRepository. Эти классы можно получить через service container Laravel:

use Laravel\Passport\TokenRepository;
use Laravel\Passport\RefreshTokenRepository;

$tokenRepository = app(TokenRepository::class);
$refreshTokenRepository = app(RefreshTokenRepository::class);

// Отозвать токен доступа...
$tokenRepository->revokeAccessToken($tokenId);

// Отозвать все refresh токены, связанные с токеном доступа...
$refreshTokenRepository->revokeRefreshTokensByAccessTokenId($tokenId);

#Очистка токенов

Когда токены были отозваны или истекли, вы можете очистить их из базы данных. Встроенная команда Artisan passport:purge сделает это за вас:

# Очистить отозванные и истёкшие токены и коды авторизации...
php artisan passport:purge

# Очистить только токены, истёкшие более 6 часов назад...
php artisan passport:purge --hours=6

# Очистить только отозванные токены и коды авторизации...
php artisan passport:purge --revoked

# Очистить только истёкшие токены и коды авторизации...
php artisan passport:purge --expired

Вы также можете настроить запланированную задачу в классе App\Console\Kernel вашего приложения для автоматической очистки токенов по расписанию:

/**
 * Определение расписания команд приложения.
 */
protected function schedule(Schedule $schedule): void
{
    $schedule->command('passport:purge')->hourly();
}

#Authorization Code Grant с PKCE

Authorization Code grant с "Proof Key for Code Exchange" (PKCE) — это безопасный способ аутентификации одностраничных или нативных приложений для доступа к вашему API. Этот grant следует использовать, когда нельзя гарантировать конфиденциальное хранение client secret или чтобы снизить риск перехвата authorization code злоумышленником. Вместо client secret при обмене authorization code на токен доступа используется комбинация "code verifier" и "code challenge".

#Создание клиента

Перед тем как ваше приложение сможет выдавать токены через authorization code grant с PKCE, необходимо создать клиента с поддержкой PKCE. Это можно сделать с помощью команды passport:client Artisan с опцией --public:

php artisan passport:client --public

#Запрос токенов

#Code Verifier и Code Challenge

Поскольку этот тип авторизации не предусматривает client secret, разработчикам необходимо сгенерировать комбинацию code verifier и code challenge для запроса токена.

Code verifier должен быть случайной строкой длиной от 43 до 128 символов, содержащей буквы, цифры и символы "-", ".", "_", "~", как определено в спецификации RFC 7636.

Code challenge должен быть строкой, закодированной в Base64 с использованием символов, безопасных для URL и имён файлов. Конечные символы '=' должны быть удалены, а также не должно быть переносов строк, пробелов или других дополнительных символов.

$encoded = base64_encode(hash('sha256', $code_verifier, true));

$codeChallenge = strtr(rtrim($encoded, '='), '+/', '-_');

#Перенаправление для авторизации

После создания клиента вы можете использовать client ID и сгенерированные code verifier и code challenge для запроса кода авторизации и access token из вашего приложения. Сначала приложение-потребитель должно сделать запрос перенаправления на маршрут /oauth/authorize вашего приложения:

use Illuminate\Http\Request;
use Illuminate\Support\Str;

Route::get('/redirect', function (Request $request) {
    $request->session()->put('state', $state = Str::random(40));

    $request->session()->put(
        'code_verifier', $code_verifier = Str::random(128)
    );

    $codeChallenge = strtr(rtrim(
        base64_encode(hash('sha256', $code_verifier, true))
    , '='), '+/', '-_');

    $query = http_build_query([
        'client_id' => 'client-id',
        'redirect_uri' => 'http://third-party-app.com/callback',
        'response_type' => 'code',
        'scope' => '',
        'state' => $state,
        'code_challenge' => $codeChallenge,
        'code_challenge_method' => 'S256',
        // 'prompt' => '', // "none", "consent", или "login"
    ]);

    return redirect('http://passport-app.test/oauth/authorize?'.$query);
});

#Конвертация кодов авторизации в access tokens

Если пользователь одобряет запрос авторизации, он будет перенаправлен обратно в приложение-потребитель. Потребитель должен проверить параметр state на соответствие значению, сохранённому до перенаправления, как в стандартном Authorization Code Grant.

Если параметр state совпадает, потребитель должен отправить POST запрос вашему приложению для получения access token. Запрос должен включать код авторизации, выданный вашим приложением при одобрении запроса пользователем, а также изначально сгенерированный code verifier:

use Illuminate\Http\Request;
use Illuminate\Support\Facades\Http;

Route::get('/callback', function (Request $request) {
    $state = $request->session()->pull('state');

    $codeVerifier = $request->session()->pull('code_verifier');

    throw_unless(
        strlen($state) > 0 && $state === $request->state,
        InvalidArgumentException::class
    );

    $response = Http::asForm()->post('http://passport-app.test/oauth/token', [
        'grant_type' => 'authorization_code',
        'client_id' => 'client-id',
        'redirect_uri' => 'http://third-party-app.com/callback',
        'code_verifier' => $codeVerifier,
        'code' => $request->code,
    ]);

    return $response->json();
});

#Токены Password Grant

Внимание

Мы больше не рекомендуем использовать токены password grant. Вместо этого следует выбрать тип гранта, рекомендованный OAuth2 Server.

OAuth2 password grant позволяет вашим другим first-party клиентам, например мобильному приложению, получить access token, используя email/имя пользователя и пароль. Это позволяет безопасно выдавать access tokens вашим first-party клиентам без необходимости проходить полный OAuth2 поток с перенаправлением и кодом авторизации.

#Создание клиента Password Grant

Перед тем как ваше приложение сможет выдавать токены через password grant, необходимо создать клиента password grant. Это можно сделать с помощью Artisan команды passport:client с опцией --password. Если вы уже запускали команду passport:install, повторно запускать не нужно:

php artisan passport:client --password

#Запрос токенов

После создания клиента password grant вы можете запросить access token, отправив POST запрос на маршрут /oauth/token с email и паролем пользователя. Этот маршрут уже зарегистрирован Passport, поэтому определять его вручную не нужно. Если запрос успешен, сервер вернёт в JSON ответе access_token и refresh_token:

use Illuminate\Support\Facades\Http;

$response = Http::asForm()->post('http://passport-app.test/oauth/token', [
    'grant_type' => 'password',
    'client_id' => 'client-id',
    'client_secret' => 'client-secret',
    'username' => 'taylor@laravel.com',
    'password' => 'my-password',
    'scope' => '',
]);

return $response->json();
Примечание

Помните, что access tokens по умолчанию имеют длительный срок жизни. Однако вы можете настроить максимальный срок жизни access token при необходимости.

#Запрос всех scopes

При использовании password grant или client credentials grant вы можете захотеть авторизовать токен для всех scopes, поддерживаемых вашим приложением. Для этого запросите scope *. Если вы запрашиваете scope *, метод can на экземпляре токена всегда будет возвращать true. Этот scope может быть назначен только токену, выданному с помощью грантов password или client_credentials:

use Illuminate\Support\Facades\Http;

$response = Http::asForm()->post('http://passport-app.test/oauth/token', [
    'grant_type' => 'password',
    'client_id' => 'client-id',
    'client_secret' => 'client-secret',
    'username' => 'taylor@laravel.com',
    'password' => 'my-password',
    'scope' => '*',
]);

#Настройка провайдера пользователей

Если ваше приложение использует более одного authentication user provider, вы можете указать, какой провайдер использовать для password grant клиента, передав опцию --provider при создании клиента через команду artisan passport:client --password. Имя провайдера должно совпадать с валидным провайдером, определённым в конфигурации config/auth.php. Затем вы можете защитить маршрут с помощью middleware, чтобы разрешить доступ только пользователям указанного провайдера.

#Настройка поля имени пользователя

При аутентификации через password grant Passport использует атрибут email вашей модели аутентификации в качестве "имени пользователя". Однако вы можете изменить это поведение, определив метод findForPassport в вашей модели:

<?php

namespace App\Models;

use Illuminate\Foundation\Auth\User as Authenticatable;
use Illuminate\Notifications\Notifiable;
use Laravel\Passport\HasApiTokens;

class User extends Authenticatable
{
    use HasApiTokens, Notifiable;

    /**
     * Найти пользователя по заданному имени пользователя.
     */
    public function findForPassport(string $username): User
    {
        return $this->where('username', $username)->first();
    }
}

#Настройка проверки пароля

При аутентификации через password grant Passport использует атрибут password вашей модели для проверки пароля. Если в вашей модели нет атрибута password или вы хотите изменить логику проверки пароля, вы можете определить метод validateForPassportPasswordGrant в вашей модели:

<?php

namespace App\Models;

use Illuminate\Foundation\Auth\User as Authenticatable;
use Illuminate\Notifications\Notifiable;
use Illuminate\Support\Facades\Hash;
use Laravel\Passport\HasApiTokens;

class User extends Authenticatable
{
    use HasApiTokens, Notifiable;

    /**
     * Проверить пароль пользователя для password grant Passport.
     */
    public function validateForPassportPasswordGrant(string $password): bool
    {
        return Hash::check($password, $this->password);
    }
}

#Токены Implicit Grant

Внимание

Мы больше не рекомендуем использовать токены implicit grant. Вместо этого следует выбрать тип гранта, рекомендованный OAuth2 Server.

Implicit grant похож на authorization code grant, но токен возвращается клиенту без обмена кода авторизации. Этот грант чаще всего используется для JavaScript или мобильных приложений, где client credentials нельзя безопасно хранить. Чтобы включить этот грант, вызовите метод enableImplicitGrant в методе boot класса App\Providers\AuthServiceProvider вашего приложения:

/**
 * Зарегистрировать любые сервисы аутентификации / авторизации.
 */
public function boot(): void
{
    Passport::enableImplicitGrant();
}

После включения гранта разработчики могут использовать client ID для запроса access token из вашего приложения. Приложение-потребитель должно сделать запрос перенаправления на маршрут /oauth/authorize вашего приложения следующим образом:

use Illuminate\Http\Request;

Route::get('/redirect', function (Request $request) {
    $request->session()->put('state', $state = Str::random(40));

    $query = http_build_query([
        'client_id' => 'client-id',
        'redirect_uri' => 'http://third-party-app.com/callback',
        'response_type' => 'token',
        'scope' => '',
        'state' => $state,
        // 'prompt' => '', // "none", "consent", или "login"
    ]);

    return redirect('http://passport-app.test/oauth/authorize?'.$query);
});
Примечание

Помните, что маршрут /oauth/authorize уже определён Passport. Вам не нужно определять его вручную.

#Токены Client Credentials Grant

Client credentials grant подходит для аутентификации между машинами. Например, вы можете использовать этот грант в плановом задании, выполняющем задачи обслуживания через API.

Перед тем как ваше приложение сможет выдавать токены через client credentials grant, необходимо создать клиента для этого гранта. Это можно сделать с помощью опции --client команды passport:client Artisan:

php artisan passport:client --client

Далее, чтобы использовать этот тип гранта, добавьте middleware CheckClientCredentials в свойство $middlewareAliases файла app/Http/Kernel.php вашего приложения:

use Laravel\Passport\Http\Middleware\CheckClientCredentials;

protected $middlewareAliases = [
    'client' => CheckClientCredentials::class,
];

Затем примените middleware к маршруту:

Route::get('/orders', function (Request $request) {
    ...
})->middleware('client');

Чтобы ограничить доступ к маршруту определёнными scopes, вы можете передать список scopes через запятую при подключении middleware client к маршруту:

Route::get('/orders', function (Request $request) {
    ...
})->middleware('client:check-status,your-scope');

#Получение токенов

Чтобы получить токен с помощью этого типа гранта, сделайте запрос к endpoint oauth/token:

use Illuminate\Support\Facades\Http;

$response = Http::asForm()->post('http://passport-app.test/oauth/token', [
    'grant_type' => 'client_credentials',
    'client_id' => 'client-id',
    'client_secret' => 'client-secret',
    'scope' => 'your-scope',
]);

return $response->json()['access_token'];

#Личные Access Tokens

Иногда пользователи хотят выдавать себе access tokens без прохождения стандартного потока с кодом авторизации и перенаправлением. Позволить пользователям создавать токены через UI вашего приложения удобно для экспериментов с API или просто как более простой способ выдачи токенов.

Примечание

Если ваше приложение в основном использует Passport для выдачи личных access tokens, рассмотрите возможность использования Laravel Sanctum — лёгкой first-party библиотеки Laravel для выдачи API access tokens.

#Создание клиента для личных access tokens

Перед тем как ваше приложение сможет выдавать личные access tokens, необходимо создать клиента для личного доступа. Это можно сделать, выполнив команду passport:client Artisan с опцией --personal. Если вы уже запускали команду passport:install, повторно запускать не нужно:

php artisan passport:client --personal

После создания клиента для личного доступа поместите ID клиента и его секрет в открытом виде в файл .env вашего приложения:

PASSPORT_PERSONAL_ACCESS_CLIENT_ID="client-id-value"
PASSPORT_PERSONAL_ACCESS_CLIENT_SECRET="unhashed-client-secret-value"

#Управление личными access tokens

После создания клиента для личного доступа вы можете выдавать токены для конкретного пользователя, используя метод createToken на экземпляре модели App\Models\User. Метод createToken принимает имя токена в качестве первого аргумента и необязательный массив scopes в качестве второго:

use App\Models\User;

$user = User::find(1);

// Создание токена без scopes...
$token = $user->createToken('Token Name')->accessToken;

// Создание токена с scopes...
$token = $user->createToken('My Token', ['place-orders'])->accessToken;

#JSON API

Passport также включает JSON API для управления личными access tokens. Вы можете использовать его вместе с собственным фронтендом, чтобы предоставить пользователям панель управления личными токенами. Ниже приведён обзор всех API endpoint для управления личными access tokens. Для удобства мы используем Axios для демонстрации HTTP-запросов к этим endpoint.

JSON API защищён middleware web и auth; поэтому его можно вызывать только из вашего приложения. Вызов из внешних источников невозможен.

#GET /oauth/scopes

Этот маршрут возвращает все scopes, определённые для вашего приложения. Вы можете использовать этот маршрут, чтобы вывести список scopes, которые пользователь может назначить личному access token:

axios.get('/oauth/scopes')
    .then(response => {
        console.log(response.data);
    });

#GET /oauth/personal-access-tokens

Этот маршрут возвращает все личные access tokens, созданные аутентифицированным пользователем. Это полезно для отображения всех токенов пользователя, чтобы он мог их редактировать или отзывать:

axios.get('/oauth/personal-access-tokens')
    .then(response => {
        console.log(response.data);
    });

#POST /oauth/personal-access-tokens

Этот маршрут создаёт новые личные access tokens. Для этого требуется два параметра: name токена и scopes, которые должны быть назначены токену:

const data = {
    name: 'Token Name',
    scopes: []
};

axios.post('/oauth/personal-access-tokens', data)
    .then(response => {
        console.log(response.data.accessToken);
    })
    .catch (response => {
        // Вывести ошибки из ответа...
    });

#DELETE /oauth/personal-access-tokens/{token-id}

Этот маршрут используется для отзыва личных access tokens:

axios.delete('/oauth/personal-access-tokens/' + tokenId);

#Защита маршрутов

#Через middleware

Passport включает authentication guard, который проверяет access tokens в входящих запросах. После настройки guard api с драйвером passport достаточно указать middleware auth:api на маршрутах, требующих валидный access token:

Route::get('/user', function () {
    // ...
})->middleware('auth:api');
Внимание

Если вы используете client credentials grant, вместо middleware auth:api следует использовать middleware client для защиты маршрутов.

#Несколько authentication guards

Если ваше приложение аутентифицирует разные типы пользователей, возможно использующих разные Eloquent модели, вам потребуется определить конфигурацию guard для каждого типа провайдера пользователей. Это позволит защищать запросы, предназначенные для конкретных провайдеров. Например, при следующей конфигурации guard в файле config/auth.php:

'api' => [
    'driver' => 'passport',
    'provider' => 'users',
],

'api-customers' => [
    'driver' => 'passport',
    'provider' => 'customers',
],

Следующий маршрут будет использовать guard api-customers, который применяет провайдера customers для аутентификации входящих запросов:

Route::get('/customer', function () {
    // ...
})->middleware('auth:api-customers');
Примечание

Для дополнительной информации о работе с несколькими провайдерами пользователей в Passport смотрите документацию по password grant.

#Передача access token

При вызове маршрутов, защищённых Passport, потребители вашего API должны указывать access token в заголовке Authorization как токен типа Bearer. Например, при использовании библиотеки Guzzle HTTP:

use Illuminate\Support\Facades\Http;

$response = Http::withHeaders([
    'Accept' => 'application/json',
    'Authorization' => 'Bearer '.$accessToken,
])->get('https://passport-app.test/api/user');

return $response->json();

#Scopes токенов

Scopes позволяют вашим API клиентам запрашивать определённый набор разрешений при запросе авторизации для доступа к аккаунту. Например, если вы создаёте e-commerce приложение, не все API потребители должны иметь возможность размещать заказы. Вместо этого вы можете разрешить им запрашивать доступ только к статусам отправки заказов. Иными словами, scopes позволяют пользователям вашего приложения ограничивать действия, которые стороннее приложение может выполнять от их имени.

#Определение scopes

Вы можете определить scopes вашего API с помощью метода Passport::tokensCan в методе boot класса App\Providers\AuthServiceProvider вашего приложения. Метод tokensCan принимает массив имён scopes и их описаний. Описание scope может быть любым и будет отображаться пользователям на экране подтверждения авторизации:

/**
 * Зарегистрировать любые сервисы аутентификации / авторизации.
 */
public function boot(): void
{
    Passport::tokensCan([
        'place-orders' => 'Размещение заказов',
        'check-status' => 'Проверка статуса заказа',
    ]);
}

#Scope по умолчанию

Если клиент не запрашивает конкретные scopes, вы можете настроить сервер Passport так, чтобы он автоматически добавлял scope(ы) по умолчанию к токену с помощью метода setDefaultScope. Обычно этот метод вызывается из метода boot класса App\Providers\AuthServiceProvider вашего приложения:

use Laravel\Passport\Passport;

Passport::tokensCan([
    'place-orders' => 'Размещение заказов',
    'check-status' => 'Проверка статуса заказа',
]);

Passport::setDefaultScope([
    'check-status',
    'place-orders',
]);
Примечание

Scopes по умолчанию Passport не применяются к личным access tokens, создаваемым пользователем.

#Назначение scopes токенам

#При запросе кодов авторизации

При запросе access token через authorization code grant потребители должны указать желаемые scopes в параметре scope строки запроса. Параметр scope должен содержать список scopes, разделённых пробелом:

Route::get('/redirect', function () {
    $query = http_build_query([
        'client_id' => 'client-id',
        'redirect_uri' => 'http://example.com/callback',
        'response_type' => 'code',
        'scope' => 'place-orders check-status',
    ]);

    return redirect('http://passport-app.test/oauth/authorize?'.$query);
});

#При выдаче личных access tokens

Если вы выдаёте личные access tokens с помощью метода createToken модели App\Models\User, вы можете передать массив желаемых scopes вторым аргументом метода:

$token = $user->createToken('My Token', ['place-orders'])->accessToken;

#Проверка scopes

Passport включает два middleware, которые можно использовать для проверки, что входящий запрос аутентифицирован токеном с заданным scope. Для начала добавьте следующие middleware в свойство $middlewareAliases файла app/Http/Kernel.php:

'scopes' => \Laravel\Passport\Http\Middleware\CheckScopes::class,
'scope' => \Laravel\Passport\Http\Middleware\CheckForAnyScope::class,

#Проверка всех scopes

Middleware scopes можно назначить маршруту, чтобы проверить, что access token входящего запроса содержит все перечисленные scopes:

Route::get('/orders', function () {
    // Access token содержит scopes "check-status" и "place-orders"...
})->middleware(['auth:api', 'scopes:check-status,place-orders']);

#Проверка хотя бы одного scope

Middleware scope можно назначить маршруту, чтобы проверить, что access token входящего запроса содержит хотя бы один из перечисленных scopes:

Route::get('/orders', function () {
    // Access token содержит либо "check-status", либо "place-orders"...
})->middleware(['auth:api', 'scope:check-status,place-orders']);

#Проверка scopes на экземпляре токена

После того как запрос с аутентификацией через access token вошёл в ваше приложение, вы всё ещё можете проверить наличие scope у токена с помощью метода tokenCan на аутентифицированном экземпляре App\Models\User:

use Illuminate\Http\Request;

Route::get('/orders', function (Request $request) {
    if ($request->user()->tokenCan('place-orders')) {
        // ...
    }
});

#Дополнительные методы для scopes

Метод scopeIds вернёт массив всех определённых ID / имён scopes:

use Laravel\Passport\Passport;

Passport::scopeIds();

Метод scopes вернёт массив всех определённых scopes в виде экземпляров Laravel\Passport\Scope:

Passport::scopes();

Метод scopesFor вернёт массив экземпляров Laravel\Passport\Scope, соответствующих заданным ID / именам:

Passport::scopesFor(['place-orders', 'check-status']);

Вы можете проверить, определён ли scope, с помощью метода hasScope:

Passport::hasScope('place-orders');

#Использование вашего API с JavaScript

При разработке API очень удобно иметь возможность использовать собственное API из JavaScript приложения. Такой подход позволяет вашему приложению использовать тот же API, который вы предоставляете внешнему миру. Один и тот же API может использоваться вашим веб-приложением, мобильными приложениями, сторонними приложениями и любыми SDK, которые вы публикуете в различных менеджерах пакетов.

Обычно, чтобы использовать API из JavaScript, нужно вручную передавать access token приложению и включать его в каждый запрос. Однако Passport включает middleware, который может сделать это за вас. Всё, что нужно — добавить middleware CreateFreshApiToken в группу middleware web в файле app/Http/Kernel.php вашего приложения:

'web' => [
    // Другие middleware...
    \Laravel\Passport\Http\Middleware\CreateFreshApiToken::class,
],
Внимание

Убедитесь, что middleware CreateFreshApiToken указан последним в стеке middleware.

Этот middleware добавит cookie laravel_token к вашим исходящим ответам. Эта cookie содержит зашифрованный JWT, который Passport использует для аутентификации API запросов из вашего JavaScript приложения. Время жизни JWT равно значению конфигурации session.lifetime. Поскольку браузер автоматически отправляет cookie с каждым последующим запросом, вы можете делать запросы к API вашего приложения без явной передачи access token:

axios.get('/api/user')
    .then(response => {
        console.log(response.data);
    });

При необходимости вы можете настроить имя cookie laravel_token с помощью метода Passport::cookie. Обычно этот метод вызывается из метода boot класса App\Providers\AuthServiceProvider вашего приложения:

/**
 * Зарегистрировать любые службы аутентификации / авторизации.
 */
public function boot(): void
{
    Passport::cookie('custom_name');
}

#Защита от CSRF

При использовании этого способа аутентификации необходимо убедиться, что в ваших запросах присутствует корректный заголовок CSRF токена. В стандартной JavaScript-структуре Laravel используется экземпляр Axios, который автоматически применяет зашифрованное значение cookie XSRF-TOKEN для отправки заголовка X-XSRF-TOKEN в запросах с того же источника.

Примечание

Если вы решите отправлять заголовок X-CSRF-TOKEN вместо X-XSRF-TOKEN, вам нужно будет использовать незашифрованный токен, предоставляемый функцией csrf_token().

#События

Passport генерирует события при выдаче access токенов и refresh токенов. Вы можете использовать эти события для удаления или отзыва других access токенов в вашей базе данных. При необходимости вы можете прикрепить слушатели к этим событиям в классе App\Providers\EventServiceProvider вашего приложения:

/**
 * Отображение слушателей событий для приложения.
 *
 * @var array
 */
protected $listen = [
    'Laravel\Passport\Events\AccessTokenCreated' => [
        'App\Listeners\RevokeOldTokens',
    ],

    'Laravel\Passport\Events\RefreshTokenCreated' => [
        'App\Listeners\PruneOldTokens',
    ],
];

#Тестирование

Метод actingAs Passport может использоваться для указания текущего аутентифицированного пользователя и его scopes. Первый аргумент метода actingAs — экземпляр пользователя, второй — массив scopes, которые должны быть предоставлены токену пользователя:

use App\Models\User;
use Laravel\Passport\Passport;

public function test_servers_can_be_created(): void
{
    Passport::actingAs(
        User::factory()->create(),
        ['create-servers']
    );

    $response = $this->post('/api/create-server');

    $response->assertStatus(201);
}

Метод actingAsClient Passport может использоваться для указания текущего аутентифицированного клиента и его scopes. Первый аргумент метода actingAsClient — экземпляр клиента, второй — массив scopes, которые должны быть предоставлены токену клиента:

use Laravel\Passport\Client;
use Laravel\Passport\Passport;

public function test_orders_can_be_retrieved(): void
{
    Passport::actingAsClient(
        Client::factory()->create(),
        ['check-status']
    );

    $response = $this->get('/api/orders');

    $response->assertStatus(200);
}