Files
laravelDocScrappy/output/12.x/passport.md
2025-09-02 15:19:23 +02:00

3068 lines
82 KiB
Markdown
Raw Permalink Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# Laravel Passport
* Introduction
* Passport or Sanctum?
* Installation
* Deploying Passport
* Upgrading Passport
* Configuration
* Token Lifetimes
* Overriding Default Models
* Overriding Routes
* Authorization Code Grant
* Managing Clients
* Requesting Tokens
* Managing Tokens
* Refreshing Tokens
* Revoking Tokens
* Purging Tokens
* Authorization Code Grant With PKCE
* Creating the Client
* Requesting Tokens
* Device Authorization Grant
* Creating a Device Code Grant Client
* Requesting Tokens
* Password Grant
* Creating a Password Grant Client
* Requesting Tokens
* Requesting All Scopes
* Customizing the User Provider
* Customizing the Username Field
* Customizing the Password Validation
* Implicit Grant
* Client Credentials Grant
* Personal Access Tokens
* Creating a Personal Access Client
* Customizing the User Provider
* Managing Personal Access Tokens
* Protecting Routes
* Via Middleware
* Passing the Access Token
* Token Scopes
* Defining Scopes
* Default Scope
* Assigning Scopes to Tokens
* Checking Scopes
* SPA Authentication
* Events
* Testing
## Introduction
[Laravel Passport](https://github.com/laravel/passport) provides a full OAuth2
server implementation for your Laravel application in a matter of minutes.
Passport is built on top of the [League OAuth2
server](https://github.com/thephpleague/oauth2-server) that is maintained by
Andy Millington and Simon Hamp.
This documentation assumes you are already familiar with OAuth2. If you do not
know anything about OAuth2, consider familiarizing yourself with the general
[terminology](https://oauth2.thephpleague.com/terminology/) and features of
OAuth2 before continuing.
### Passport or Sanctum?
Before getting started, you may wish to determine if your application would be
better served by Laravel Passport or [Laravel Sanctum](/docs/12.x/sanctum). If
your application absolutely needs to support OAuth2, then you should use
Laravel Passport.
However, if you are attempting to authenticate a single-page application,
mobile application, or issue API tokens, you should use [Laravel
Sanctum](/docs/12.x/sanctum). Laravel Sanctum does not support OAuth2;
however, it provides a much simpler API authentication development experience.
## Installation
You may install Laravel Passport via the `install:api` Artisan command:
1php artisan install:api --passport
php artisan install:api --passport
This command will publish and run the database migrations necessary for
creating the tables your application needs to store OAuth2 clients and access
tokens. The command will also create the encryption keys required to generate
secure access tokens.
After running the `install:api` command, add the
`Laravel\Passport\HasApiTokens` trait and
`Laravel\Passport\Contracts\OAuthenticatable` interface to your
`App\Models\User` model. This trait will provide a few helper methods to your
model which allow you to inspect the authenticated user's token and scopes:
1<?php
2 
3namespace App\Models;
4 
5use Illuminate\Database\Eloquent\Factories\HasFactory;
6use Illuminate\Foundation\Auth\User as Authenticatable;
7use Illuminate\Notifications\Notifiable;
8use Laravel\Passport\Contracts\OAuthenticatable;
9use Laravel\Passport\HasApiTokens;
10 
11class User extends Authenticatable implements OAuthenticatable
12{
13 use HasApiTokens, HasFactory, Notifiable;
14}
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Foundation\Auth\User as Authenticatable;
use Illuminate\Notifications\Notifiable;
use Laravel\Passport\Contracts\OAuthenticatable;
use Laravel\Passport\HasApiTokens;
class User extends Authenticatable implements OAuthenticatable
{
use HasApiTokens, HasFactory, Notifiable;
}
Finally, in your application's `config/auth.php` configuration file, you
should define an `api` authentication guard and set the `driver` option to
`passport`. This will instruct your application to use Passport's `TokenGuard`
when authenticating incoming API requests:
1'guards' => [
2 'web' => [
3 'driver' => 'session',
4 'provider' => 'users',
5 ],
6 
7 'api' => [
8 'driver' => 'passport',
9 'provider' => 'users',
10 ],
11],
'guards' => [
'web' => [
'driver' => 'session',
'provider' => 'users',
],
'api' => [
'driver' => 'passport',
'provider' => 'users',
],
],
### Deploying Passport
When deploying Passport to your application's servers for the first time, you
will likely need to run the `passport:keys` command. This command generates
the encryption keys Passport needs in order to generate access tokens. The
generated keys are not typically kept in source control:
1php artisan passport:keys
php artisan passport:keys
If necessary, you may define the path where Passport's keys should be loaded
from. You may use the `Passport::loadKeysFrom` method to accomplish this.
Typically, this method should be called from the `boot` method of your
application's `App\Providers\AppServiceProvider` class:
1/**
2 * Bootstrap any application services.
3 */
4public function boot(): void
5{
6 Passport::loadKeysFrom(__DIR__.'/../secrets/oauth');
7}
/**
* Bootstrap any application services.
*/
public function boot(): void
{
Passport::loadKeysFrom(__DIR__.'/../secrets/oauth');
}
#### Loading Keys From the Environment
Alternatively, you may publish Passport's configuration file using the
`vendor:publish` Artisan command:
1php artisan vendor:publish --tag=passport-config
php artisan vendor:publish --tag=passport-config
After the configuration file has been published, you may load your
application's encryption keys by defining them as environment variables:
1PASSPORT_PRIVATE_KEY="-----BEGIN RSA PRIVATE KEY-----
2<private key here>
3-----END RSA PRIVATE KEY-----"
4 
5PASSPORT_PUBLIC_KEY="-----BEGIN PUBLIC KEY-----
6<public key here>
7-----END PUBLIC KEY-----"
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-----"
### Upgrading Passport
When upgrading to a new major version of Passport, it's important that you
carefully review [the upgrade
guide](https://github.com/laravel/passport/blob/master/UPGRADE.md).
## Configuration
### Token Lifetimes
By default, Passport issues long-lived access tokens that expire after one
year. If you would like to configure a longer / shorter token lifetime, you
may use the `tokensExpireIn`, `refreshTokensExpireIn`, and
`personalAccessTokensExpireIn` methods. These methods should be called from
the `boot` method of your application's `App\Providers\AppServiceProvider`
class:
1use Carbon\CarbonInterval;
2 
3/**
4 * Bootstrap any application services.
5 */
6public function boot(): void
7{
8 Passport::tokensExpireIn(CarbonInterval::days(15));
9 Passport::refreshTokensExpireIn(CarbonInterval::days(30));
10 Passport::personalAccessTokensExpireIn(CarbonInterval::months(6));
11}
use Carbon\CarbonInterval;
/**
* Bootstrap any application services.
*/
public function boot(): void
{
Passport::tokensExpireIn(CarbonInterval::days(15));
Passport::refreshTokensExpireIn(CarbonInterval::days(30));
Passport::personalAccessTokensExpireIn(CarbonInterval::months(6));
}
The `expires_at` columns on Passport's database tables are read-only and for
display purposes only. When issuing tokens, Passport stores the expiration
information within the signed and encrypted tokens. If you need to invalidate
a token you should revoke it.
### Overriding Default Models
You are free to extend the models used internally by Passport by defining your
own model and extending the corresponding Passport model:
1use Laravel\Passport\Client as PassportClient;
2 
3class Client extends PassportClient
4{
5 // ...
6}
use Laravel\Passport\Client as PassportClient;
class Client extends PassportClient
{
// ...
}
After defining your model, you may instruct Passport to use your custom model
via the `Laravel\Passport\Passport` class. Typically, you should inform
Passport about your custom models in the `boot` method of your application's
`App\Providers\AppServiceProvider` class:
1use App\Models\Passport\AuthCode;
2use App\Models\Passport\Client;
3use App\Models\Passport\DeviceCode;
4use App\Models\Passport\RefreshToken;
5use App\Models\Passport\Token;
6use Laravel\Passport\Passport;
7 
8/**
9 * Bootstrap any application services.
10 */
11public function boot(): void
12{
13 Passport::useTokenModel(Token::class);
14 Passport::useRefreshTokenModel(RefreshToken::class);
15 Passport::useAuthCodeModel(AuthCode::class);
16 Passport::useClientModel(Client::class);
17 Passport::useDeviceCodeModel(DeviceCode::class);
18}
use App\Models\Passport\AuthCode;
use App\Models\Passport\Client;
use App\Models\Passport\DeviceCode;
use App\Models\Passport\RefreshToken;
use App\Models\Passport\Token;
use Laravel\Passport\Passport;
/**
* Bootstrap any application services.
*/
public function boot(): void
{
Passport::useTokenModel(Token::class);
Passport::useRefreshTokenModel(RefreshToken::class);
Passport::useAuthCodeModel(AuthCode::class);
Passport::useClientModel(Client::class);
Passport::useDeviceCodeModel(DeviceCode::class);
}
### Overriding Routes
Sometimes you may wish to customize the routes defined by Passport. To achieve
this, you first need to ignore the routes registered by Passport by adding
`Passport::ignoreRoutes` to the `register` method of your application's
`AppServiceProvider`:
1use Laravel\Passport\Passport;
2 
3/**
4 * Register any application services.
5 */
6public function register(): void
7{
8 Passport::ignoreRoutes();
9}
use Laravel\Passport\Passport;
/**
* Register any application services.
*/
public function register(): void
{
Passport::ignoreRoutes();
}
Then, you may copy the routes defined by Passport in [its routes
file](https://github.com/laravel/passport/blob/master/routes/web.php) to your
application's `routes/web.php` file and modify them to your liking:
1Route::group([
2 'as' => 'passport.',
3 'prefix' => config('passport.path', 'oauth'),
4 'namespace' => '\Laravel\Passport\Http\Controllers',
5], function () {
6 // Passport routes...
7});
Route::group([
'as' => 'passport.',
'prefix' => config('passport.path', 'oauth'),
'namespace' => '\Laravel\Passport\Http\Controllers',
], function () {
// Passport routes...
});
## Authorization Code Grant
Using OAuth2 via authorization codes is how most developers are familiar with
OAuth2. When using authorization codes, a client application will redirect a
user to your server where they will either approve or deny the request to
issue an access token to the client.
To get started, we need to instruct Passport how to return our "authorization"
view.
All the authorization view's rendering logic may be customized using the
appropriate methods available via the `Laravel\Passport\Passport` class.
Typically, you should call this method from the `boot` method of your
application's `App\Providers\AppServiceProvider` class:
1use Inertia\Inertia;
2use Laravel\Passport\Passport;
3 
4/**
5 * Bootstrap any application services.
6 */
7public function boot(): void
8{
9 // By providing a view name...
10 Passport::authorizationView('auth.oauth.authorize');
11 
12 // By providing a closure...
13 Passport::authorizationView(
14 fn ($parameters) => Inertia::render('Auth/OAuth/Authorize', [
15 'request' => $parameters['request'],
16 'authToken' => $parameters['authToken'],
17 'client' => $parameters['client'],
18 'user' => $parameters['user'],
19 'scopes' => $parameters['scopes'],
20 ])
21 );
22}
use Inertia\Inertia;
use Laravel\Passport\Passport;
/**
* Bootstrap any application services.
*/
public function boot(): void
{
// By providing a view name...
Passport::authorizationView('auth.oauth.authorize');
// By providing a closure...
Passport::authorizationView(
fn ($parameters) => Inertia::render('Auth/OAuth/Authorize', [
'request' => $parameters['request'],
'authToken' => $parameters['authToken'],
'client' => $parameters['client'],
'user' => $parameters['user'],
'scopes' => $parameters['scopes'],
])
);
}
Passport will automatically define the `/oauth/authorize` route that returns
this view. Your `auth.oauth.authorize` template should include a form that
makes a POST request to the `passport.authorizations.approve` route to approve
the authorization and a form that makes a DELETE request to the
`passport.authorizations.deny` route to deny the authorization. The
`passport.authorizations.approve` and `passport.authorizations.deny` routes
expect `state`, `client_id`, and `auth_token` fields.
### Managing Clients
Developers building applications that need to interact with your application's
API will need to register their application with yours by creating a "client".
Typically, this consists of providing the name of their application and a URI
that your application can redirect to after users approve their request for
authorization.
#### First-Party Clients
The simplest way to create a client is using the `passport:client` Artisan
command. This command may be used to create first-party clients or testing
your OAuth2 functionality. When you run the `passport:client` command,
Passport will prompt you for more information about your client and will
provide you with a client ID and secret:
1php artisan passport:client
php artisan passport:client
If you would like to allow multiple redirect URIs for your client, you may
specify them using a comma-delimited list when prompted for the URI by the
`passport:client` command. Any URIs which contain commas should be URI
encoded:
1https://third-party-app.com/callback,https://example.com/oauth/redirect
https://third-party-app.com/callback,https://example.com/oauth/redirect
#### Third-Party Clients
Since your application's users will not be able to utilize the
`passport:client` command, you may use `createAuthorizationCodeGrantClient`
method of the `Laravel\Passport\ClientRepository` class to register a client
for a given user:
1use App\Models\User;
2use Laravel\Passport\ClientRepository;
3 
4$user = User::find($userId);
5 
6// Creating an OAuth app client that belongs to the given user...
7$client = app(ClientRepository::class)->createAuthorizationCodeGrantClient(
8 user: $user,
9 name: 'Example App',
10 redirectUris: ['https://third-party-app.com/callback'],
11 confidential: false,
12 enableDeviceFlow: true
13);
14 
15// Retrieving all the OAuth app clients that belong to the user...
16$clients = $user->oauthApps()->get();
use App\Models\User;
use Laravel\Passport\ClientRepository;
$user = User::find($userId);
// Creating an OAuth app client that belongs to the given user...
$client = app(ClientRepository::class)->createAuthorizationCodeGrantClient(
user: $user,
name: 'Example App',
redirectUris: ['https://third-party-app.com/callback'],
confidential: false,
enableDeviceFlow: true
);
// Retrieving all the OAuth app clients that belong to the user...
$clients = $user->oauthApps()->get();
The `createAuthorizationCodeGrantClient` method returns an instance of
`Laravel\Passport\Client`. You may display the `$client->id` as the client ID
and `$client->plainSecret` as the client secret to the user.
### Requesting Tokens
#### Redirecting for Authorization
Once a client has been created, developers may use their client ID and secret
to request an authorization code and access token from your application.
First, the consuming application should make a redirect request to your
application's `/oauth/authorize` route like so:
1use Illuminate\Http\Request;
2use Illuminate\Support\Str;
3 
4Route::get('/redirect', function (Request $request) {
5 $request->session()->put('state', $state = Str::random(40));
6 
7 $query = http_build_query([
8 'client_id' => 'your-client-id',
9 'redirect_uri' => 'https://third-party-app.com/callback',
10 'response_type' => 'code',
11 'scope' => 'user:read orders:create',
12 'state' => $state,
13 // 'prompt' => '', // "none", "consent", or "login"
14 ]);
15 
16 return redirect('https://passport-app.test/oauth/authorize?'.$query);
17});
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' => 'your-client-id',
'redirect_uri' => 'https://third-party-app.com/callback',
'response_type' => 'code',
'scope' => 'user:read orders:create',
'state' => $state,
// 'prompt' => '', // "none", "consent", or "login"
]);
return redirect('https://passport-app.test/oauth/authorize?'.$query);
});
The `prompt` parameter may be used to specify the authentication behavior of
the Passport application.
If the `prompt` value is `none`, Passport will always throw an authentication
error if the user is not already authenticated with the Passport application.
If the value is `consent`, Passport will always display the authorization
approval screen, even if all scopes were previously granted to the consuming
application. When the value is `login`, the Passport application will always
prompt the user to re-login to the application, even if they already have an
existing session.
If no `prompt` value is provided, the user will be prompted for authorization
only if they have not previously authorized access to the consuming
application for the requested scopes.
Remember, the `/oauth/authorize` route is already defined by Passport. You do
not need to manually define this route.
#### Approving the Request
When receiving authorization requests, Passport will automatically respond
based on the value of `prompt` parameter (if present) and may display a
template to the user allowing them to approve or deny the authorization
request. If they approve the request, they will be redirected back to the
`redirect_uri` that was specified by the consuming application. The
`redirect_uri` must match the `redirect` URL that was specified when the
client was created.
Sometimes you may wish to skip the authorization prompt, such as when
authorizing a first-party client. You may accomplish this by extending the
`Client` model and defining a `skipsAuthorization` method. If
`skipsAuthorization` returns `true` the client will be approved and the user
will be redirected back to the `redirect_uri` immediately, unless the
consuming application has explicitly set the `prompt` parameter when
redirecting for authorization:
1<?php
2 
3namespace App\Models\Passport;
4 
5use Illuminate\Contracts\Auth\Authenticatable;
6use Laravel\Passport\Client as BaseClient;
7 
8class Client extends BaseClient
9{
10 /**
11 * Determine if the client should skip the authorization prompt.
12 *
13 * @param \Laravel\Passport\Scope[] $scopes
14 */
15 public function skipsAuthorization(Authenticatable $user, array $scopes): bool
16 {
17 return $this->firstParty();
18 }
19}
<?php
namespace App\Models\Passport;
use Illuminate\Contracts\Auth\Authenticatable;
use Laravel\Passport\Client as BaseClient;
class Client extends BaseClient
{
/**
* Determine if the client should skip the authorization prompt.
*
* @param \Laravel\Passport\Scope[] $scopes
*/
public function skipsAuthorization(Authenticatable $user, array $scopes): bool
{
return $this->firstParty();
}
}
#### Converting Authorization Codes to Access Tokens
If the user approves the authorization request, they will be redirected back
to the consuming application. The consumer should first verify the `state`
parameter against the value that was stored prior to the redirect. If the
state parameter matches then the consumer should issue a `POST` request to
your application to request an access token. The request should include the
authorization code that was issued by your application when the user approved
the authorization request:
1use Illuminate\Http\Request;
2use Illuminate\Support\Facades\Http;
3 
4Route::get('/callback', function (Request $request) {
5 $state = $request->session()->pull('state');
6 
7 throw_unless(
8 strlen($state) > 0 && $state === $request->state,
9 InvalidArgumentException::class,
10 'Invalid state value.'
11 );
12 
13 $response = Http::asForm()->post('https://passport-app.test/oauth/token', [
14 'grant_type' => 'authorization_code',
15 'client_id' => 'your-client-id',
16 'client_secret' => 'your-client-secret',
17 'redirect_uri' => 'https://third-party-app.com/callback',
18 'code' => $request->code,
19 ]);
20 
21 return $response->json();
22});
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,
'Invalid state value.'
);
$response = Http::asForm()->post('https://passport-app.test/oauth/token', [
'grant_type' => 'authorization_code',
'client_id' => 'your-client-id',
'client_secret' => 'your-client-secret',
'redirect_uri' => 'https://third-party-app.com/callback',
'code' => $request->code,
]);
return $response->json();
});
This `/oauth/token` route will return a JSON response containing
`access_token`, `refresh_token`, and `expires_in` attributes. The `expires_in`
attribute contains the number of seconds until the access token expires.
Like the `/oauth/authorize` route, the `/oauth/token` route is defined for you
by Passport. There is no need to manually define this route.
### Managing Tokens
You may retrieve user's authorized tokens using the `tokens` method of the
`Laravel\Passport\HasApiTokens` trait. For example, this may be used to offer
your users a dashboard to keep track of their connections with third-party
applications:
1use App\Models\User;
2use Illuminate\Database\Eloquent\Collection;
3use Illuminate\Support\Facades\Date;
4use Laravel\Passport\Token;
5 
6$user = User::find($userId);
7 
8// Retrieving all of the valid tokens for the user...
9$tokens = $user->tokens()
10 ->where('revoked', false)
11 ->where('expires_at', '>', Date::now())
12 ->get();
13 
14// Retrieving all the user's connections to third-party OAuth app clients...
15$connections = $tokens->load('client')
16 ->reject(fn (Token $token) => $token->client->firstParty())
17 ->groupBy('client_id')
18 ->map(fn (Collection $tokens) => [
19 'client' => $tokens->first()->client,
20 'scopes' => $tokens->pluck('scopes')->flatten()->unique()->values()->all(),
21 'tokens_count' => $tokens->count(),
22 ])
23 ->values();
use App\Models\User;
use Illuminate\Database\Eloquent\Collection;
use Illuminate\Support\Facades\Date;
use Laravel\Passport\Token;
$user = User::find($userId);
// Retrieving all of the valid tokens for the user...
$tokens = $user->tokens()
->where('revoked', false)
->where('expires_at', '>', Date::now())
->get();
// Retrieving all the user's connections to third-party OAuth app clients...
$connections = $tokens->load('client')
->reject(fn (Token $token) => $token->client->firstParty())
->groupBy('client_id')
->map(fn (Collection $tokens) => [
'client' => $tokens->first()->client,
'scopes' => $tokens->pluck('scopes')->flatten()->unique()->values()->all(),
'tokens_count' => $tokens->count(),
])
->values();
### Refreshing Tokens
If your application issues short-lived access tokens, users will need to
refresh their access tokens via the refresh token that was provided to them
when the access token was issued:
1use Illuminate\Support\Facades\Http;
2 
3$response = Http::asForm()->post('https://passport-app.test/oauth/token', [
4 'grant_type' => 'refresh_token',
5 'refresh_token' => 'the-refresh-token',
6 'client_id' => 'your-client-id',
7 'client_secret' => 'your-client-secret', // Required for confidential clients only...
8 'scope' => 'user:read orders:create',
9]);
10 
11return $response->json();
use Illuminate\Support\Facades\Http;
$response = Http::asForm()->post('https://passport-app.test/oauth/token', [
'grant_type' => 'refresh_token',
'refresh_token' => 'the-refresh-token',
'client_id' => 'your-client-id',
'client_secret' => 'your-client-secret', // Required for confidential clients only...
'scope' => 'user:read orders:create',
]);
return $response->json();
This `/oauth/token` route will return a JSON response containing
`access_token`, `refresh_token`, and `expires_in` attributes. The `expires_in`
attribute contains the number of seconds until the access token expires.
### Revoking Tokens
You may revoke a token by using the `revoke` method on the
`Laravel\Passport\Token` model. You may revoke a token's refresh token using
the `revoke` method on the `Laravel\Passport\RefreshToken` model:
1use Laravel\Passport\Passport;
2use Laravel\Passport\Token;
3 
4$token = Passport::token()->find($tokenId);
5 
6// Revoke an access token...
7$token->revoke();
8 
9// Revoke the token's refresh token...
10$token->refreshToken?->revoke();
11 
12// Revoke all of the user's tokens...
13User::find($userId)->tokens()->each(function (Token $token) {
14 $token->revoke();
15 $token->refreshToken?->revoke();
16});
use Laravel\Passport\Passport;
use Laravel\Passport\Token;
$token = Passport::token()->find($tokenId);
// Revoke an access token...
$token->revoke();
// Revoke the token's refresh token...
$token->refreshToken?->revoke();
// Revoke all of the user's tokens...
User::find($userId)->tokens()->each(function (Token $token) {
$token->revoke();
$token->refreshToken?->revoke();
});
### Purging Tokens
When tokens have been revoked or expired, you might want to purge them from
the database. Passport's included `passport:purge` Artisan command can do this
for you:
1# Purge revoked and expired tokens, auth codes, and device codes...
2php artisan passport:purge
3 
4# Only purge tokens expired for more than 6 hours...
5php artisan passport:purge --hours=6
6 
7# Only purge revoked tokens, auth codes, and device codes...
8php artisan passport:purge --revoked
9 
10# Only purge expired tokens, auth codes, and device codes...
11php artisan passport:purge --expired
# Purge revoked and expired tokens, auth codes, and device codes...
php artisan passport:purge
# Only purge tokens expired for more than 6 hours...
php artisan passport:purge --hours=6
# Only purge revoked tokens, auth codes, and device codes...
php artisan passport:purge --revoked
# Only purge expired tokens, auth codes, and device codes...
php artisan passport:purge --expired
You may also configure a [scheduled job](/docs/12.x/scheduling) in your
application's `routes/console.php` file to automatically prune your tokens on
a schedule:
1use Illuminate\Support\Facades\Schedule;
2 
3Schedule::command('passport:purge')->hourly();
use Illuminate\Support\Facades\Schedule;
Schedule::command('passport:purge')->hourly();
## Authorization Code Grant With PKCE
The Authorization Code grant with "Proof Key for Code Exchange" (PKCE) is a
secure way to authenticate single page applications or mobile applications to
access your API. This grant should be used when you can't guarantee that the
client secret will be stored confidentially or in order to mitigate the threat
of having the authorization code intercepted by an attacker. A combination of
a "code verifier" and a "code challenge" replaces the client secret when
exchanging the authorization code for an access token.
### Creating the Client
Before your application can issue tokens via the authorization code grant with
PKCE, you will need to create a PKCE-enabled client. You may do this using the
`passport:client` Artisan command with the `--public` option:
1php artisan passport:client --public
php artisan passport:client --public
### Requesting Tokens
#### Code Verifier and Code Challenge
As this authorization grant does not provide a client secret, developers will
need to generate a combination of a code verifier and a code challenge in
order to request a token.
The code verifier should be a random string of between 43 and 128 characters
containing letters, numbers, and `"-"`, `"."`, `"_"`, `"~"` characters, as
defined in the [RFC 7636 specification](https://tools.ietf.org/html/rfc7636).
The code challenge should be a Base64 encoded string with URL and filename-
safe characters. The trailing `'='` characters should be removed and no line
breaks, whitespace, or other additional characters should be present.
1$encoded = base64_encode(hash('sha256', $codeVerifier, true));
2 
3$codeChallenge = strtr(rtrim($encoded, '='), '+/', '-_');
$encoded = base64_encode(hash('sha256', $codeVerifier, true));
$codeChallenge = strtr(rtrim($encoded, '='), '+/', '-_');
#### Redirecting for Authorization
Once a client has been created, you may use the client ID and the generated
code verifier and code challenge to request an authorization code and access
token from your application. First, the consuming application should make a
redirect request to your application's `/oauth/authorize` route:
1use Illuminate\Http\Request;
2use Illuminate\Support\Str;
3 
4Route::get('/redirect', function (Request $request) {
5 $request->session()->put('state', $state = Str::random(40));
6 
7 $request->session()->put(
8 'code_verifier', $codeVerifier = Str::random(128)
9 );
10 
11 $codeChallenge = strtr(rtrim(
12 base64_encode(hash('sha256', $codeVerifier, true))
13 , '='), '+/', '-_');
14 
15 $query = http_build_query([
16 'client_id' => 'your-client-id',
17 'redirect_uri' => 'https://third-party-app.com/callback',
18 'response_type' => 'code',
19 'scope' => 'user:read orders:create',
20 'state' => $state,
21 'code_challenge' => $codeChallenge,
22 'code_challenge_method' => 'S256',
23 // 'prompt' => '', // "none", "consent", or "login"
24 ]);
25 
26 return redirect('https://passport-app.test/oauth/authorize?'.$query);
27});
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', $codeVerifier = Str::random(128)
);
$codeChallenge = strtr(rtrim(
base64_encode(hash('sha256', $codeVerifier, true))
, '='), '+/', '-_');
$query = http_build_query([
'client_id' => 'your-client-id',
'redirect_uri' => 'https://third-party-app.com/callback',
'response_type' => 'code',
'scope' => 'user:read orders:create',
'state' => $state,
'code_challenge' => $codeChallenge,
'code_challenge_method' => 'S256',
// 'prompt' => '', // "none", "consent", or "login"
]);
return redirect('https://passport-app.test/oauth/authorize?'.$query);
});
#### Converting Authorization Codes to Access Tokens
If the user approves the authorization request, they will be redirected back
to the consuming application. The consumer should verify the `state` parameter
against the value that was stored prior to the redirect, as in the standard
Authorization Code Grant.
If the state parameter matches, the consumer should issue a `POST` request to
your application to request an access token. The request should include the
authorization code that was issued by your application when the user approved
the authorization request along with the originally generated code verifier:
1use Illuminate\Http\Request;
2use Illuminate\Support\Facades\Http;
3 
4Route::get('/callback', function (Request $request) {
5 $state = $request->session()->pull('state');
6 
7 $codeVerifier = $request->session()->pull('code_verifier');
8 
9 throw_unless(
10 strlen($state) > 0 && $state === $request->state,
11 InvalidArgumentException::class
12 );
13 
14 $response = Http::asForm()->post('https://passport-app.test/oauth/token', [
15 'grant_type' => 'authorization_code',
16 'client_id' => 'your-client-id',
17 'redirect_uri' => 'https://third-party-app.com/callback',
18 'code_verifier' => $codeVerifier,
19 'code' => $request->code,
20 ]);
21 
22 return $response->json();
23});
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('https://passport-app.test/oauth/token', [
'grant_type' => 'authorization_code',
'client_id' => 'your-client-id',
'redirect_uri' => 'https://third-party-app.com/callback',
'code_verifier' => $codeVerifier,
'code' => $request->code,
]);
return $response->json();
});
## Device Authorization Grant
The OAuth2 device authorization grant allows browserless or limited input
devices, such as TVs and game consoles, to obtain an access token by
exchanging a "device code". When using device flow, the device client will
instruct the user to use a secondary device, such as a computer or a
smartphone and connect to your server where they will enter the provided "user
code" and either approve or deny the access request.
To get started, we need to instruct Passport how to return our "user code" and
"authorization" views.
All the authorization view's rendering logic may be customized using the
appropriate methods available via the `Laravel\Passport\Passport` class.
Typically, you should call this method from the `boot` method of your
application's `App\Providers\AppServiceProvider` class.
1use Inertia\Inertia;
2use Laravel\Passport\Passport;
3 
4/**
5 * Bootstrap any application services.
6 */
7public function boot(): void
8{
9 // By providing a view name...
10 Passport::deviceUserCodeView('auth.oauth.device.user-code');
11 Passport::deviceAuthorizationView('auth.oauth.device.authorize');
12 
13 // By providing a closure...
14 Passport::deviceUserCodeView(
15 fn ($parameters) => Inertia::render('Auth/OAuth/Device/UserCode')
16 );
17 
18 Passport::deviceAuthorizationView(
19 fn ($parameters) => Inertia::render('Auth/OAuth/Device/Authorize', [
20 'request' => $parameters['request'],
21 'authToken' => $parameters['authToken'],
22 'client' => $parameters['client'],
23 'user' => $parameters['user'],
24 'scopes' => $parameters['scopes'],
25 ])
26 );
27 
28 // ...
29}
use Inertia\Inertia;
use Laravel\Passport\Passport;
/**
* Bootstrap any application services.
*/
public function boot(): void
{
// By providing a view name...
Passport::deviceUserCodeView('auth.oauth.device.user-code');
Passport::deviceAuthorizationView('auth.oauth.device.authorize');
// By providing a closure...
Passport::deviceUserCodeView(
fn ($parameters) => Inertia::render('Auth/OAuth/Device/UserCode')
);
Passport::deviceAuthorizationView(
fn ($parameters) => Inertia::render('Auth/OAuth/Device/Authorize', [
'request' => $parameters['request'],
'authToken' => $parameters['authToken'],
'client' => $parameters['client'],
'user' => $parameters['user'],
'scopes' => $parameters['scopes'],
])
);
// ...
}
Passport will automatically define routes that return these views. Your
`auth.oauth.device.user-code` template should include a form that makes a GET
request to the `passport.device.authorizations.authorize` route. The
`passport.device.authorizations.authorize` route expects a `user_code` query
parameter.
Your `auth.oauth.device.authorize` template should include a form that makes a
POST request to the `passport.device.authorizations.approve` route to approve
the authorization and a form that makes a DELETE request to the
`passport.device.authorizations.deny` route to deny the authorization. The
`passport.device.authorizations.approve` and
`passport.device.authorizations.deny` routes expect `state`, `client_id`, and
`auth_token` fields.
### Creating a Device Authorization Grant Client
Before your application can issue tokens via the device authorization grant,
you will need to create a device flow enabled client. You may do this using
the `passport:client` Artisan command with the `--device` option. This command
will create a first-party device flow enabled client and provide you with a
client ID and secret:
1php artisan passport:client --device
php artisan passport:client --device
Additionally, you may use `createDeviceAuthorizationGrantClient` method on the
`ClientRepository` class to register a third-party client that belongs to the
given user:
1use App\Models\User;
2use Laravel\Passport\ClientRepository;
3 
4$user = User::find($userId);
5 
6$client = app(ClientRepository::class)->createDeviceAuthorizationGrantClient(
7 user: $user,
8 name: 'Example Device',
9 confidential: false,
10);
use App\Models\User;
use Laravel\Passport\ClientRepository;
$user = User::find($userId);
$client = app(ClientRepository::class)->createDeviceAuthorizationGrantClient(
user: $user,
name: 'Example Device',
confidential: false,
);
### Requesting Tokens
#### Requesting a Device Code
Once a client has been created, developers may use their client ID to request
a device code from your application. First, the consuming device should make a
`POST` request to your application's `/oauth/device/code` route to request a
device code:
1use Illuminate\Support\Facades\Http;
2 
3$response = Http::asForm()->post('https://passport-app.test/oauth/device/code', [
4 'client_id' => 'your-client-id',
5 'scope' => 'user:read orders:create',
6]);
7 
8return $response->json();
use Illuminate\Support\Facades\Http;
$response = Http::asForm()->post('https://passport-app.test/oauth/device/code', [
'client_id' => 'your-client-id',
'scope' => 'user:read orders:create',
]);
return $response->json();
This will return a JSON response containing `device_code`, `user_code`,
`verification_uri`, `interval`, and `expires_in` attributes. The `expires_in`
attribute contains the number of seconds until the device code expires. The
`interval` attribute contains the number of seconds the consuming device
should wait between requests when polling `/oauth/token` route to avoid rate
limit errors.
Remember, the `/oauth/device/code` route is already defined by Passport. You
do not need to manually define this route.
#### Displaying the Verification URI and User Code
Once a device code request has been obtained, the consuming device should
instruct the user to use another device and visit the provided
`verification_uri` and enter the `user_code` in order to approve the
authorization request.
#### Polling Token Request
Since the user will be using a separate device to grant (or deny) access, the
consuming device should poll your application's `/oauth/token` route to
determine when the user has responded to the request. The consuming device
should use the minimum polling `interval` provided in the JSON response when
requesting device code to avoid rate limit errors:
1use Illuminate\Support\Facades\Http;
2use Illuminate\Support\Sleep;
3 
4$interval = 5;
5 
6do {
7 Sleep::for($interval)->seconds();
8 
9 $response = Http::asForm()->post('https://passport-app.test/oauth/token', [
10 'grant_type' => 'urn:ietf:params:oauth:grant-type:device_code',
11 'client_id' => 'your-client-id',
12 'client_secret' => 'your-client-secret', // Required for confidential clients only...
13 'device_code' => 'the-device-code',
14 ]);
15 
16 if ($response->json('error') === 'slow_down') {
17 $interval += 5;
18 }
19} while (in_array($response->json('error'), ['authorization_pending', 'slow_down']));
20 
21return $response->json();
use Illuminate\Support\Facades\Http;
use Illuminate\Support\Sleep;
$interval = 5;
do {
Sleep::for($interval)->seconds();
$response = Http::asForm()->post('https://passport-app.test/oauth/token', [
'grant_type' => 'urn:ietf:params:oauth:grant-type:device_code',
'client_id' => 'your-client-id',
'client_secret' => 'your-client-secret', // Required for confidential clients only...
'device_code' => 'the-device-code',
]);
if ($response->json('error') === 'slow_down') {
$interval += 5;
}
} while (in_array($response->json('error'), ['authorization_pending', 'slow_down']));
return $response->json();
If the user has approved the authorization request, this will return a JSON
response containing `access_token`, `refresh_token`, and `expires_in`
attributes. The `expires_in` attribute contains the number of seconds until
the access token expires.
## Password Grant
We no longer recommend using password grant tokens. Instead, you should choose
[a grant type that is currently recommended by OAuth2
Server](https://oauth2.thephpleague.com/authorization-server/which-grant/).
The OAuth2 password grant allows your other first-party clients, such as a
mobile application, to obtain an access token using an email address /
username and password. This allows you to issue access tokens securely to your
first-party clients without requiring your users to go through the entire
OAuth2 authorization code redirect flow.
To enable the password grant, call the `enablePasswordGrant` method in the
`boot` method of your application's `App\Providers\AppServiceProvider` class:
1/**
2 * Bootstrap any application services.
3 */
4public function boot(): void
5{
6 Passport::enablePasswordGrant();
7}
/**
* Bootstrap any application services.
*/
public function boot(): void
{
Passport::enablePasswordGrant();
}
### Creating a Password Grant Client
Before your application can issue tokens via the password grant, you will need
to create a password grant client. You may do this using the `passport:client`
Artisan command with the `--password` option.
1php artisan passport:client --password
php artisan passport:client --password
### Requesting Tokens
Once you have enabled the grant and have created a password grant client, you
may request an access token by issuing a `POST` request to the `/oauth/token`
route with the user's email address and password. Remember, this route is
already registered by Passport so there is no need to define it manually. If
the request is successful, you will receive an `access_token` and
`refresh_token` in the JSON response from the server:
1use Illuminate\Support\Facades\Http;
2 
3$response = Http::asForm()->post('https://passport-app.test/oauth/token', [
4 'grant_type' => 'password',
5 'client_id' => 'your-client-id',
6 'client_secret' => 'your-client-secret', // Required for confidential clients only...
7 'username' => '[[email protected]](/cdn-cgi/l/email-protection)',
8 'password' => 'my-password',
9 'scope' => 'user:read orders:create',
10]);
11 
12return $response->json();
use Illuminate\Support\Facades\Http;
$response = Http::asForm()->post('https://passport-app.test/oauth/token', [
'grant_type' => 'password',
'client_id' => 'your-client-id',
'client_secret' => 'your-client-secret', // Required for confidential clients only...
'username' => '[[email protected]](/cdn-cgi/l/email-protection)',
'password' => 'my-password',
'scope' => 'user:read orders:create',
]);
return $response->json();
Remember, access tokens are long-lived by default. However, you are free to
configure your maximum access token lifetime if needed.
### Requesting All Scopes
When using the password grant or client credentials grant, you may wish to
authorize the token for all of the scopes supported by your application. You
can do this by requesting the `*` scope. If you request the `*` scope, the
`can` method on the token instance will always return `true`. This scope may
only be assigned to a token that is issued using the `password` or
`client_credentials` grant:
1use Illuminate\Support\Facades\Http;
2 
3$response = Http::asForm()->post('https://passport-app.test/oauth/token', [
4 'grant_type' => 'password',
5 'client_id' => 'your-client-id',
6 'client_secret' => 'your-client-secret', // Required for confidential clients only...
7 'username' => '[[email protected]](/cdn-cgi/l/email-protection)',
8 'password' => 'my-password',
9 'scope' => '*',
10]);
use Illuminate\Support\Facades\Http;
$response = Http::asForm()->post('https://passport-app.test/oauth/token', [
'grant_type' => 'password',
'client_id' => 'your-client-id',
'client_secret' => 'your-client-secret', // Required for confidential clients only...
'username' => '[[email protected]](/cdn-cgi/l/email-protection)',
'password' => 'my-password',
'scope' => '*',
]);
### Customizing the User Provider
If your application uses more than one [authentication user
provider](/docs/12.x/authentication#introduction), you may specify which user
provider the password grant client uses by providing a `--provider` option
when creating the client via the `artisan passport:client --password` command.
The given provider name should match a valid provider defined in your
application's `config/auth.php` configuration file. You can then protect your
route using middleware to ensure that only users from the guard's specified
provider are authorized.
### Customizing the Username Field
When authenticating using the password grant, Passport will use the `email`
attribute of your authenticatable model as the "username". However, you may
customize this behavior by defining a `findForPassport` method on your model:
1<?php
2 
3namespace App\Models;
4 
5use Illuminate\Foundation\Auth\User as Authenticatable;
6use Illuminate\Notifications\Notifiable;
7use Laravel\Passport\Contracts\OAuthenticatable;
8use Laravel\Passport\HasApiTokens;
9 
10class User extends Authenticatable implements OAuthenticatable
11{
12 use HasApiTokens, Notifiable;
13 
14 /**
15 * Find the user instance for the given username.
16 */
17 public function findForPassport(string $username): User
18 {
19 return $this->where('username', $username)->first();
20 }
21}
<?php
namespace App\Models;
use Illuminate\Foundation\Auth\User as Authenticatable;
use Illuminate\Notifications\Notifiable;
use Laravel\Passport\Contracts\OAuthenticatable;
use Laravel\Passport\HasApiTokens;
class User extends Authenticatable implements OAuthenticatable
{
use HasApiTokens, Notifiable;
/**
* Find the user instance for the given username.
*/
public function findForPassport(string $username): User
{
return $this->where('username', $username)->first();
}
}
### Customizing the Password Validation
When authenticating using the password grant, Passport will use the `password`
attribute of your model to validate the given password. If your model does not
have a `password` attribute or you wish to customize the password validation
logic, you can define a `validateForPassportPasswordGrant` method on your
model:
1<?php
2 
3namespace App\Models;
4 
5use Illuminate\Foundation\Auth\User as Authenticatable;
6use Illuminate\Notifications\Notifiable;
7use Illuminate\Support\Facades\Hash;
8use Laravel\Passport\Contracts\OAuthenticatable;
9use Laravel\Passport\HasApiTokens;
10 
11class User extends Authenticatable implements OAuthenticatable
12{
13 use HasApiTokens, Notifiable;
14 
15 /**
16 * Validate the password of the user for the Passport password grant.
17 */
18 public function validateForPassportPasswordGrant(string $password): bool
19 {
20 return Hash::check($password, $this->password);
21 }
22}
<?php
namespace App\Models;
use Illuminate\Foundation\Auth\User as Authenticatable;
use Illuminate\Notifications\Notifiable;
use Illuminate\Support\Facades\Hash;
use Laravel\Passport\Contracts\OAuthenticatable;
use Laravel\Passport\HasApiTokens;
class User extends Authenticatable implements OAuthenticatable
{
use HasApiTokens, Notifiable;
/**
* Validate the password of the user for the Passport password grant.
*/
public function validateForPassportPasswordGrant(string $password): bool
{
return Hash::check($password, $this->password);
}
}
## Implicit Grant
We no longer recommend using implicit grant tokens. Instead, you should choose
[a grant type that is currently recommended by OAuth2
Server](https://oauth2.thephpleague.com/authorization-server/which-grant/).
The implicit grant is similar to the authorization code grant; however, the
token is returned to the client without exchanging an authorization code. This
grant is most commonly used for JavaScript or mobile applications where the
client credentials can't be securely stored. To enable the grant, call the
`enableImplicitGrant` method in the `boot` method of your application's
`App\Providers\AppServiceProvider` class:
1/**
2 * Bootstrap any application services.
3 */
4public function boot(): void
5{
6 Passport::enableImplicitGrant();
7}
/**
* Bootstrap any application services.
*/
public function boot(): void
{
Passport::enableImplicitGrant();
}
Before your application can issue tokens via the implicit grant, you will need
to create an implicit grant client. You may do this using the
`passport:client` Artisan command with the `--implicit` option.
1php artisan passport:client --implicit
php artisan passport:client --implicit
Once the grant has been enabled and an implicit client has been created,
developers may use their client ID to request an access token from your
application. The consuming application should make a redirect request to your
application's `/oauth/authorize` route like so:
1use Illuminate\Http\Request;
2 
3Route::get('/redirect', function (Request $request) {
4 $request->session()->put('state', $state = Str::random(40));
5 
6 $query = http_build_query([
7 'client_id' => 'your-client-id',
8 'redirect_uri' => 'https://third-party-app.com/callback',
9 'response_type' => 'token',
10 'scope' => 'user:read orders:create',
11 'state' => $state,
12 // 'prompt' => '', // "none", "consent", or "login"
13 ]);
14 
15 return redirect('https://passport-app.test/oauth/authorize?'.$query);
16});
use Illuminate\Http\Request;
Route::get('/redirect', function (Request $request) {
$request->session()->put('state', $state = Str::random(40));
$query = http_build_query([
'client_id' => 'your-client-id',
'redirect_uri' => 'https://third-party-app.com/callback',
'response_type' => 'token',
'scope' => 'user:read orders:create',
'state' => $state,
// 'prompt' => '', // "none", "consent", or "login"
]);
return redirect('https://passport-app.test/oauth/authorize?'.$query);
});
Remember, the `/oauth/authorize` route is already defined by Passport. You do
not need to manually define this route.
## Client Credentials Grant
The client credentials grant is suitable for machine-to-machine
authentication. For example, you might use this grant in a scheduled job which
is performing maintenance tasks over an API.
Before your application can issue tokens via the client credentials grant, you
will need to create a client credentials grant client. You may do this using
the `--client` option of the `passport:client` Artisan command:
1php artisan passport:client --client
php artisan passport:client --client
Next, assign the
`Laravel\Passport\Http\Middleware\EnsureClientIsResourceOwner` middleware to a
route:
1use Laravel\Passport\Http\Middleware\EnsureClientIsResourceOwner;
2 
3Route::get('/orders', function (Request $request) {
4 // Access token is valid and the client is resource owner...
5})->middleware(EnsureClientIsResourceOwner::class);
use Laravel\Passport\Http\Middleware\EnsureClientIsResourceOwner;
Route::get('/orders', function (Request $request) {
// Access token is valid and the client is resource owner...
})->middleware(EnsureClientIsResourceOwner::class);
To restrict access to the route to specific scopes, you may provide a list of
the required scopes to the `using` method`:
1Route::get('/orders', function (Request $request) {
2 // Access token is valid, the client is resource owner, and has both "servers:read" and "servers:create" scopes...
3})->middleware(EnsureClientIsResourceOwner::using('servers:read', 'servers:create'));
Route::get('/orders', function (Request $request) {
// Access token is valid, the client is resource owner, and has both "servers:read" and "servers:create" scopes...
})->middleware(EnsureClientIsResourceOwner::using('servers:read', 'servers:create'));
### Retrieving Tokens
To retrieve a token using this grant type, make a request to the `oauth/token`
endpoint:
1use Illuminate\Support\Facades\Http;
2 
3$response = Http::asForm()->post('https://passport-app.test/oauth/token', [
4 'grant_type' => 'client_credentials',
5 'client_id' => 'your-client-id',
6 'client_secret' => 'your-client-secret',
7 'scope' => 'servers:read servers:create',
8]);
9 
10return $response->json()['access_token'];
use Illuminate\Support\Facades\Http;
$response = Http::asForm()->post('https://passport-app.test/oauth/token', [
'grant_type' => 'client_credentials',
'client_id' => 'your-client-id',
'client_secret' => 'your-client-secret',
'scope' => 'servers:read servers:create',
]);
return $response->json()['access_token'];
## Personal Access Tokens
Sometimes, your users may want to issue access tokens to themselves without
going through the typical authorization code redirect flow. Allowing users to
issue tokens to themselves via your application's UI can be useful for
allowing users to experiment with your API or may serve as a simpler approach
to issuing access tokens in general.
If your application is using Passport primarily to issue personal access
tokens, consider using [Laravel Sanctum](/docs/12.x/sanctum), Laravel's light-
weight first-party library for issuing API access tokens.
### Creating a Personal Access Client
Before your application can issue personal access tokens, you will need to
create a personal access client. You may do this by executing the
`passport:client` Artisan command with the `--personal` option. If you have
already run the `passport:install` command, you do not need to run this
command:
1php artisan passport:client --personal
php artisan passport:client --personal
### Customizing the User Provider
If your application uses more than one [authentication user
provider](/docs/12.x/authentication#introduction), you may specify which user
provider the personal access grant client uses by providing a `--provider`
option when creating the client via the `artisan passport:client --personal`
command. The given provider name should match a valid provider defined in your
application's `config/auth.php` configuration file. You can then protect your
route using middleware to ensure that only users from the guard's specified
provider are authorized.
### Managing Personal Access Tokens
Once you have created a personal access client, you may issue tokens for a
given user using the `createToken` method on the `App\Models\User` model
instance. The `createToken` method accepts the name of the token as its first
argument and an optional array of scopes as its second argument:
1use App\Models\User;
2use Illuminate\Support\Facades\Date;
3use Laravel\Passport\Token;
4 
5$user = User::find($userId);
6 
7// Creating a token without scopes...
8$token = $user->createToken('My Token')->accessToken;
9 
10// Creating a token with scopes...
11$token = $user->createToken('My Token', ['user:read', 'orders:create'])->accessToken;
12 
13// Creating a token with all scopes...
14$token = $user->createToken('My Token', ['*'])->accessToken;
15 
16// Retrieving all the valid personal access tokens that belong to the user...
17$tokens = $user->tokens()
18 ->with('client')
19 ->where('revoked', false)
20 ->where('expires_at', '>', Date::now())
21 ->get()
22 ->filter(fn (Token $token) => $token->client->hasGrantType('personal_access'));
use App\Models\User;
use Illuminate\Support\Facades\Date;
use Laravel\Passport\Token;
$user = User::find($userId);
// Creating a token without scopes...
$token = $user->createToken('My Token')->accessToken;
// Creating a token with scopes...
$token = $user->createToken('My Token', ['user:read', 'orders:create'])->accessToken;
// Creating a token with all scopes...
$token = $user->createToken('My Token', ['*'])->accessToken;
// Retrieving all the valid personal access tokens that belong to the user...
$tokens = $user->tokens()
->with('client')
->where('revoked', false)
->where('expires_at', '>', Date::now())
->get()
->filter(fn (Token $token) => $token->client->hasGrantType('personal_access'));
## Protecting Routes
### Via Middleware
Passport includes an [authentication guard](/docs/12.x/authentication#adding-
custom-guards) that will validate access tokens on incoming requests. Once you
have configured the `api` guard to use the `passport` driver, you only need to
specify the `auth:api` middleware on any routes that should require a valid
access token:
1Route::get('/user', function () {
2 // Only API authenticated users may access this route...
3})->middleware('auth:api');
Route::get('/user', function () {
// Only API authenticated users may access this route...
})->middleware('auth:api');
If you are using the client credentials grant, you should use the
`Laravel\Passport\Http\Middleware\EnsureClientIsResourceOwner` middleware to
protect your routes instead of the `auth:api` middleware.
#### Multiple Authentication Guards
If your application authenticates different types of users that perhaps use
entirely different Eloquent models, you will likely need to define a guard
configuration for each user provider type in your application. This allows you
to protect requests intended for specific user providers. For example, given
the following guard configuration the `config/auth.php` configuration file:
1'guards' => [
2 'api' => [
3 'driver' => 'passport',
4 'provider' => 'users',
5 ],
6 
7 'api-customers' => [
8 'driver' => 'passport',
9 'provider' => 'customers',
10 ],
11],
'guards' => [
'api' => [
'driver' => 'passport',
'provider' => 'users',
],
'api-customers' => [
'driver' => 'passport',
'provider' => 'customers',
],
],
The following route will utilize the `api-customers` guard, which uses the
`customers` user provider, to authenticate incoming requests:
1Route::get('/customer', function () {
2 // ...
3})->middleware('auth:api-customers');
Route::get('/customer', function () {
// ...
})->middleware('auth:api-customers');
For more information on using multiple user providers with Passport, please
consult the personal access tokens documentation and password grant
documentation.
### Passing the Access Token
When calling routes that are protected by Passport, your application's API
consumers should specify their access token as a `Bearer` token in the
`Authorization` header of their request. For example, when using the `Http`
Facade:
1use Illuminate\Support\Facades\Http;
2 
3$response = Http::withHeaders([
4 'Accept' => 'application/json',
5 'Authorization' => "Bearer $accessToken",
6])->get('https://passport-app.test/api/user');
7 
8return $response->json();
use Illuminate\Support\Facades\Http;
$response = Http::withHeaders([
'Accept' => 'application/json',
'Authorization' => "Bearer $accessToken",
])->get('https://passport-app.test/api/user');
return $response->json();
## Token Scopes
Scopes allow your API clients to request a specific set of permissions when
requesting authorization to access an account. For example, if you are
building an e-commerce application, not all API consumers will need the
ability to place orders. Instead, you may allow the consumers to only request
authorization to access order shipment statuses. In other words, scopes allow
your application's users to limit the actions a third-party application can
perform on their behalf.
### Defining Scopes
You may define your API's scopes using the `Passport::tokensCan` method in the
`boot` method of your application's `App\Providers\AppServiceProvider` class.
The `tokensCan` method accepts an array of scope names and scope descriptions.
The scope description may be anything you wish and will be displayed to users
on the authorization approval screen:
1/**
2 * Bootstrap any application services.
3 */
4public function boot(): void
5{
6 Passport::tokensCan([
7 'user:read' => 'Retrieve the user info',
8 'orders:create' => 'Place orders',
9 'orders:read:status' => 'Check order status',
10 ]);
11}
/**
* Bootstrap any application services.
*/
public function boot(): void
{
Passport::tokensCan([
'user:read' => 'Retrieve the user info',
'orders:create' => 'Place orders',
'orders:read:status' => 'Check order status',
]);
}
### Default Scope
If a client does not request any specific scopes, you may configure your
Passport server to attach default scopes to the token using the
`defaultScopes` method. Typically, you should call this method from the `boot`
method of your application's `App\Providers\AppServiceProvider` class:
1use Laravel\Passport\Passport;
2 
3Passport::tokensCan([
4 'user:read' => 'Retrieve the user info',
5 'orders:create' => 'Place orders',
6 'orders:read:status' => 'Check order status',
7]);
8 
9Passport::defaultScopes([
10 'user:read',
11 'orders:create',
12]);
use Laravel\Passport\Passport;
Passport::tokensCan([
'user:read' => 'Retrieve the user info',
'orders:create' => 'Place orders',
'orders:read:status' => 'Check order status',
]);
Passport::defaultScopes([
'user:read',
'orders:create',
]);
### Assigning Scopes to Tokens
#### When Requesting Authorization Codes
When requesting an access token using the authorization code grant, consumers
should specify their desired scopes as the `scope` query string parameter. The
`scope` parameter should be a space-delimited list of scopes:
1Route::get('/redirect', function () {
2 $query = http_build_query([
3 'client_id' => 'your-client-id',
4 'redirect_uri' => 'https://third-party-app.com/callback',
5 'response_type' => 'code',
6 'scope' => 'user:read orders:create',
7 ]);
8 
9 return redirect('https://passport-app.test/oauth/authorize?'.$query);
10});
Route::get('/redirect', function () {
$query = http_build_query([
'client_id' => 'your-client-id',
'redirect_uri' => 'https://third-party-app.com/callback',
'response_type' => 'code',
'scope' => 'user:read orders:create',
]);
return redirect('https://passport-app.test/oauth/authorize?'.$query);
});
#### When Issuing Personal Access Tokens
If you are issuing personal access tokens using the `App\Models\User` model's
`createToken` method, you may pass the array of desired scopes as the second
argument to the method:
1$token = $user->createToken('My Token', ['orders:create'])->accessToken;
$token = $user->createToken('My Token', ['orders:create'])->accessToken;
### Checking Scopes
Passport includes two middleware that may be used to verify that an incoming
request is authenticated with a token that has been granted a given scope.
#### Check For All Scopes
The `Laravel\Passport\Http\Middleware\CheckToken` middleware may be assigned
to a route to verify that the incoming request's access token has all the
listed scopes:
1use Laravel\Passport\Http\Middleware\CheckToken;
2 
3Route::get('/orders', function () {
4 // Access token has both "orders:read" and "orders:create" scopes...
5})->middleware(['auth:api', CheckToken::using('orders:read', 'orders:create')]);
use Laravel\Passport\Http\Middleware\CheckToken;
Route::get('/orders', function () {
// Access token has both "orders:read" and "orders:create" scopes...
})->middleware(['auth:api', CheckToken::using('orders:read', 'orders:create')]);
#### Check for Any Scopes
The `Laravel\Passport\Http\Middleware\CheckTokenForAnyScope` middleware may be
assigned to a route to verify that the incoming request's access token has _at
least one_ of the listed scopes:
1use Laravel\Passport\Http\Middleware\CheckTokenForAnyScope;
2 
3Route::get('/orders', function () {
4 // Access token has either "orders:read" or "orders:create" scope...
5})->middleware(['auth:api', CheckTokenForAnyScope::using('orders:read', 'orders:create')]);
use Laravel\Passport\Http\Middleware\CheckTokenForAnyScope;
Route::get('/orders', function () {
// Access token has either "orders:read" or "orders:create" scope...
})->middleware(['auth:api', CheckTokenForAnyScope::using('orders:read', 'orders:create')]);
#### Checking Scopes on a Token Instance
Once an access token authenticated request has entered your application, you
may still check if the token has a given scope using the `tokenCan` method on
the authenticated `App\Models\User` instance:
1use Illuminate\Http\Request;
2 
3Route::get('/orders', function (Request $request) {
4 if ($request->user()->tokenCan('orders:create')) {
5 // ...
6 }
7});
use Illuminate\Http\Request;
Route::get('/orders', function (Request $request) {
if ($request->user()->tokenCan('orders:create')) {
// ...
}
});
#### Additional Scope Methods
The `scopeIds` method will return an array of all defined IDs / names:
1use Laravel\Passport\Passport;
2 
3Passport::scopeIds();
use Laravel\Passport\Passport;
Passport::scopeIds();
The `scopes` method will return an array of all defined scopes as instances of
`Laravel\Passport\Scope`:
1Passport::scopes();
Passport::scopes();
The `scopesFor` method will return an array of `Laravel\Passport\Scope`
instances matching the given IDs / names:
1Passport::scopesFor(['user:read', 'orders:create']);
Passport::scopesFor(['user:read', 'orders:create']);
You may determine if a given scope has been defined using the `hasScope`
method:
1Passport::hasScope('orders:create');
Passport::hasScope('orders:create');
## SPA Authentication
When building an API, it can be extremely useful to be able to consume your
own API from your JavaScript application. This approach to API development
allows your own application to consume the same API that you are sharing with
the world. The same API may be consumed by your web application, mobile
applications, third-party applications, and any SDKs that you may publish on
various package managers.
Typically, if you want to consume your API from your JavaScript application,
you would need to manually send an access token to the application and pass it
with each request to your application. However, Passport includes a middleware
that can handle this for you. All you need to do is append the
`CreateFreshApiToken` middleware to the `web` middleware group in your
application's `bootstrap/app.php` file:
1use Laravel\Passport\Http\Middleware\CreateFreshApiToken;
2 
3->withMiddleware(function (Middleware $middleware) {
4 $middleware->web(append: [
5 CreateFreshApiToken::class,
6 ]);
7})
use Laravel\Passport\Http\Middleware\CreateFreshApiToken;
->withMiddleware(function (Middleware $middleware) {
$middleware->web(append: [
CreateFreshApiToken::class,
]);
})
You should ensure that the `CreateFreshApiToken` middleware is the last
middleware listed in your middleware stack.
This middleware will attach a `laravel_token` cookie to your outgoing
responses. This cookie contains an encrypted JWT that Passport will use to
authenticate API requests from your JavaScript application. The JWT has a
lifetime equal to your `session.lifetime` configuration value. Now, since the
browser will automatically send the cookie with all subsequent requests, you
may make requests to your application's API without explicitly passing an
access token:
1axios.get('/api/user')
2 .then(response => {
3 console.log(response.data);
4 });
axios.get('/api/user')
.then(response => {
console.log(response.data);
});
#### Customizing the Cookie Name
If needed, you can customize the `laravel_token` cookie's name using the
`Passport::cookie` method. Typically, this method should be called from the
`boot` method of your application's `App\Providers\AppServiceProvider` class:
1/**
2 * Bootstrap any application services.
3 */
4public function boot(): void
5{
6 Passport::cookie('custom_name');
7}
/**
* Bootstrap any application services.
*/
public function boot(): void
{
Passport::cookie('custom_name');
}
#### CSRF Protection
When using this method of authentication, you will need to ensure a valid CSRF
token header is included in your requests. The default Laravel JavaScript
scaffolding included with the skeleton application and all starter kits
includes an [Axios](https://github.com/axios/axios) instance, which will
automatically use the encrypted `XSRF-TOKEN` cookie value to send an `X-XSRF-
TOKEN` header on same-origin requests.
If you choose to send the `X-CSRF-TOKEN` header instead of `X-XSRF-TOKEN`, you
will need to use the unencrypted token provided by `csrf_token()`.
## Events
Passport raises events when issuing access tokens and refresh tokens. You may
[listen for these events](/docs/12.x/events) to prune or revoke other access
tokens in your database:
Event Name
---
`Laravel\Passport\Events\AccessTokenCreated`
`Laravel\Passport\Events\AccessTokenRevoked`
`Laravel\Passport\Events\RefreshTokenCreated`
## Testing
Passport's `actingAs` method may be used to specify the currently
authenticated user as well as its scopes. The first argument given to the
`actingAs` method is the user instance and the second is an array of scopes
that should be granted to the user's token:
Pest PHPUnit
1use App\Models\User;
2use Laravel\Passport\Passport;
3 
4test('orders can be created', function () {
5 Passport::actingAs(
6 User::factory()->create(),
7 ['orders:create']
8 );
9 
10 $response = $this->post('/api/orders');
11 
12 $response->assertStatus(201);
13});
use App\Models\User;
use Laravel\Passport\Passport;
test('orders can be created', function () {
Passport::actingAs(
User::factory()->create(),
['orders:create']
);
$response = $this->post('/api/orders');
$response->assertStatus(201);
});
1use App\Models\User;
2use Laravel\Passport\Passport;
3 
4public function test_orders_can_be_created(): void
5{
6 Passport::actingAs(
7 User::factory()->create(),
8 ['orders:create']
9 );
10 
11 $response = $this->post('/api/orders');
12 
13 $response->assertStatus(201);
14}
use App\Models\User;
use Laravel\Passport\Passport;
public function test_orders_can_be_created(): void
{
Passport::actingAs(
User::factory()->create(),
['orders:create']
);
$response = $this->post('/api/orders');
$response->assertStatus(201);
}
Passport's `actingAsClient` method may be used to specify the currently
authenticated client as well as its scopes. The first argument given to the
`actingAsClient` method is the client instance and the second is an array of
scopes that should be granted to the client's token:
Pest PHPUnit
1use Laravel\Passport\Client;
2use Laravel\Passport\Passport;
3 
4test('servers can be retrieved', function () {
5 Passport::actingAsClient(
6 Client::factory()->create(),
7 ['servers:read']
8 );
9 
10 $response = $this->get('/api/servers');
11 
12 $response->assertStatus(200);
13});
use Laravel\Passport\Client;
use Laravel\Passport\Passport;
test('servers can be retrieved', function () {
Passport::actingAsClient(
Client::factory()->create(),
['servers:read']
);
$response = $this->get('/api/servers');
$response->assertStatus(200);
});
1use Laravel\Passport\Client;
2use Laravel\Passport\Passport;
3 
4public function test_servers_can_be_retrieved(): void
5{
6 Passport::actingAsClient(
7 Client::factory()->create(),
8 ['servers:read']
9 );
10 
11 $response = $this->get('/api/servers');
12 
13 $response->assertStatus(200);
14}
use Laravel\Passport\Client;
use Laravel\Passport\Passport;
public function test_servers_can_be_retrieved(): void
{
Passport::actingAsClient(
Client::factory()->create(),
['servers:read']
);
$response = $this->get('/api/servers');
$response->assertStatus(200);
}