Skip to content
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
199 changes: 199 additions & 0 deletions resources/boost/skills/passport-development/SKILL.blade.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,199 @@
---
name: passport-development
description: "Develops OAuth2 API authentication with Laravel Passport. Activates when installing or configuring Passport; setting up OAuth2 grants (authorization code, client credentials, personal access tokens, device authorization); managing OAuth clients; protecting API routes with token authentication; defining or checking token scopes; configuring SPA cookie authentication; handling token lifetimes and refresh tokens; or when the user mentions Passport, OAuth2, API tokens, bearer tokens, or API authentication. Make sure to use this skill whenever the user works with OAuth2, API tokens, or third-party API access, even if they don't explicitly mention Passport."
license: MIT
metadata:
author: laravel
---
@php
/** @var \Laravel\Boost\Install\GuidelineAssist $assist */
@endphp
# Passport OAuth2 Authentication

## Documentation First

**Always use `search-docs` before writing Passport code.** The documentation covers every grant type, configuration option, and edge case in detail. This skill teaches you how to navigate Passport — the docs have the implementation specifics.

```
search-docs(queries: ["Passport installation"], packages: ["laravel/framework@12.x"])
```

The Passport docs live under the `laravel/framework` package — not `laravel/passport`.

## When to Apply

Activate this skill when:

- Installing or configuring Passport
- Setting up OAuth2 authorization grants
- Creating or managing OAuth clients
- Protecting API routes with token authentication
- Defining or checking token scopes
- Configuring SPA cookie-based authentication
- Choosing between Passport and Sanctum

## Passport vs. Sanctum

**Passport** is a full OAuth2 server — use it when third-party applications need to consume your API and when you need OAuth2 authorization code grants, client credentials for machine-to-machine auth, or device authorization flow.

**Sanctum** is simpler — use it when first-party SPAs, third parties, or mobile apps consume the API but you don't need the full OAuth2 grant flows.

## Installation

Three steps are always required:

### 1. Install Passport

```bash
{{ $assist->artisanCommand('install:api --passport') }}
```

This publishes migrations, generates encryption keys, and registers routes.

### 2. Configure the User model

The User model needs both the `HasApiTokens` trait AND the `OAuthenticatable` interface. Missing the interface is the most common Passport setup mistake — it causes runtime errors that can be confusing to debug.

```php
use Laravel\Passport\Contracts\OAuthenticatable;
use Laravel\Passport\HasApiTokens;

class User extends Authenticatable implements OAuthenticatable
{
use HasApiTokens;
}
```

### 3. Configure the auth guard

The `api` guard must use the `passport` driver in `config/auth.php`. Using `token` or `sanctum` here silently breaks Passport authentication.

```php
'guards' => [
'api' => [
'driver' => 'passport',
'provider' => 'users',
],
],
```

## Choosing a Grant Type

Matching the right grant to the use case is the most important Passport decision. Use `search-docs` for implementation details of any grant.

| Use Case | Grant Type | Client Flag |
|----------|-----------|-------------|
| Third-party app accessing user data | Authorization Code | (default) |
| Mobile/SPA without client secret | Authorization Code + PKCE | `--public` |
| Machine-to-machine, no user context | Client Credentials | `--client` |
| User-generated API keys | Personal Access Tokens | `--personal` |
| Smart TV, CLI, IoT devices | Device Authorization | `--device` |

**Legacy grants** (Password, Implicit) are disabled by default and not recommended. They must be explicitly enabled with `Passport::enablePasswordGrant()` or `Passport::enableImplicitGrant()`.

## Client Management

Create clients with the appropriate flag for the grant type:

```bash
{{ $assist->artisanCommand('passport:client') }} # Authorization code
{{ $assist->artisanCommand('passport:client --public') }} # PKCE (no secret)
{{ $assist->artisanCommand('passport:client --client') }} # Client credentials
{{ $assist->artisanCommand('passport:client --personal') }} # Personal access tokens
{{ $assist->artisanCommand('passport:client --device') }} # Device authorization
```

Additional flags: `--name=`, `--redirect_uri=`, `--provider=`.

Client secrets are hashed by default — the plain-text secret is only shown at creation time and cannot be retrieved later.

## Protecting Routes

Apply `auth:api` middleware. Clients send tokens via the `Authorization: Bearer <token>` header.

```php
Route::get('/user', function (Request $request) {
return $request->user();
})->middleware('auth:api');
```

### Scope Enforcement

Scope middleware must come alongside `auth:api`:

- `CheckToken::using('scope1', 'scope2')` — requires ALL listed scopes
- `CheckTokenForAnyScope::using('scope1', 'scope2')` — requires ANY listed scope
- `EnsureClientIsResourceOwner::using('scope1')` — restricts to client credential tokens

```php
use Laravel\Passport\Http\Middleware\CheckToken;

Route::get('/orders', function () {
// ...
})->middleware(['auth:api', CheckToken::using('orders:read')]);
```

### Programmatic scope checking

```php
if ($request->user()->tokenCan('place-orders')) {
// ...
}
```

Use `search-docs` for full scope middleware registration and usage patterns.

## Key Configuration

Configure in `AppServiceProvider::boot()`. Use `search-docs` for the full list of options.

```php
// Token lifetimes (each is independent)
Passport::tokensExpireIn(now()->addDays(15));
Passport::refreshTokensExpireIn(now()->addDays(30));
Passport::personalAccessTokensExpireIn(now()->addMonths(6));

// Define scopes
Passport::tokensCan([
'place-orders' => 'Place orders',
'check-status' => 'Check order status',
]);
```

## SPA Cookie Authentication

For first-party SPAs, the `CreateFreshApiToken` middleware issues a `laravel_token` cookie containing an encrypted JWT. The SPA must include CSRF tokens — missing the `X-CSRF-TOKEN` or `X-XSRF-TOKEN` header causes 419 errors.

Use `search-docs` for setup details — this feature has specific CSRF and cookie configuration requirements.

## Testing

Passport provides helpers to bypass full OAuth flows in tests:

```php
Passport::actingAs($user, ['scope1', 'scope2']);
Passport::actingAsClient($client, ['scope1']);
```

## Token Maintenance

```bash
{{ $assist->artisanCommand('passport:purge') }} # Purge revoked & expired
{{ $assist->artisanCommand('passport:purge --revoked') }} # Only revoked
{{ $assist->artisanCommand('passport:purge --expired') }} # Only expired
```

Schedule `passport:purge` for regular expired token clean-up.

## Events

All in `Laravel\Passport\Events`: `AccessTokenCreated`, `AccessTokenRevoked`, `RefreshTokenCreated`.

## Common Pitfalls

- **Missing `OAuthenticatable` interface** — both the `HasApiTokens` trait and the `OAuthenticatable` interface are required on the User model. Missing the interface causes runtime errors.
- **Wrong guard driver** — the `api` guard must use `passport`, not `token` or `sanctum`. This fails silently.
- **Token lifetime confusion** — access token, refresh token, and personal access token lifetimes are all independent settings.
- **Missing CSRF for SPA cookie auth** — `CreateFreshApiToken` requires CSRF tokens. Use `Passport::ignoreCsrfToken()` only if you understand the security implications.
- **Client secrets are hashed** — the plain-text secret is only available at creation time.
- **Legacy grants are disabled** — Password and Implicit grants must be explicitly enabled and are not recommended.
Loading