Laravel Sanctum vs Passport 2026年版: API認証の選び方と面接対策

Laravel SanctumとPassportの違いを実践的なコード例とともに解説します。SPA認証、APIトークン、OAuth2の実装方法と、技術面接で頻出する質問への回答例を紹介します。

Laravel Sanctum vs Passport API認証の比較

Laravel SanctumとPassportは異なるAPI認証ニーズに対応しており、誤った選択は不必要な複雑さやセキュリティの脆弱性につながります。本記事では、実践的なコード例と実際の面接質問を通じて、両パッケージの違いを詳しく解説します。

選択の指針

SanctumはSPA認証とシンプルなAPIトークンに適しています。Passportは認可コード、クライアントクレデンシャル、リフレッシュトークンを含む完全なOAuth2を実装します。多くのアプリケーションではSanctumで十分です。

Laravel Sanctum vs Passport: 基本的な違い

Sanctumは、ファーストパーティアプリケーション向けに設計された軽量なトークンベース認証を提供します。SPAにはCookieベースのセッション認証を、モバイルアプリやシンプルなAPIにはパーソナルアクセストークンを使用します。

Passportは完全なOAuth2仕様を実装しており、認可サーバー、クライアントクレデンシャルグラント、マシン間認証を含みます。この複雑さは、サードパーティアクセスの認可が必要なアプリケーションに適しています。

| 機能 | Sanctum | Passport | |---------|---------|----------| | 主な用途 | SPA、モバイルアプリ、シンプルなAPI | サードパーティOAuth2、マシン間通信 | | トークン形式 | シンプルなハッシュトークン | OAuth2スコープ付きJWT | | セッション認証 | 対応(Cookieベース) | 非対応 | | OAuth2グラント | なし | 完全仕様対応 | | パッケージサイズ | 最小限 | 大規模 | | 設定 | シンプル | 複雑 |

SanctumによるSPA認証の実装

SanctumのSPA認証は、APIトークンではなくLaravelのセッションCookieに依存します。フロントエンドとバックエンドは同じトップレベルドメインを共有する必要があります。

config/sanctum.phpphp
return [
    'stateful' => explode(',', env('SANCTUM_STATEFUL_DOMAINS', sprintf(
        '%s%s',
        'localhost,localhost:3000,127.0.0.1,127.0.0.1:8000,::1',
        env('APP_URL') ? ','.parse_url(env('APP_URL'), PHP_URL_HOST) : ''
    ))),

    'expiration' => null, // Tokens never expire by default

    'middleware' => [
        'verify_csrf_token' => App\Http\Middleware\VerifyCsrfToken::class,
        'encrypt_cookies' => App\Http\Middleware\EncryptCookies::class,
    ],
];

SPAは認証済みリクエストを行う前に、CSRFクッキーエンドポイントを呼び出す必要があります。これによりセッションが確立され、XSRF-TOKENクッキーが設定されます。

javascript
// Frontend: Initialize CSRF protection before login
async function initializeAuth() {
    await fetch('/sanctum/csrf-cookie', {
        credentials: 'include'
    });
}

async function login(email, password) {
    await initializeAuth();
    
    const response = await fetch('/api/login', {
        method: 'POST',
        headers: {
            'Content-Type': 'application/json',
            'X-XSRF-TOKEN': getCookie('XSRF-TOKEN'),
            'Accept': 'application/json'
        },
        credentials: 'include',
        body: JSON.stringify({ email, password })
    });
    
    return response.json();
}

SanctumによるAPIトークン認証

モバイルアプリケーションやサードパーティ連携では、セッションCookieの代わりにパーソナルアクセストークンを使用します。Sanctumはこれらのトークンをデータベースにsha-256ハッシュとして保存します。

app/Http/Controllers/AuthController.phpphp
namespace App\Http\Controllers;

use App\Models\User;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Hash;
use Illuminate\Validation\ValidationException;

class AuthController extends Controller
{
    public function createToken(Request $request)
    {
        $request->validate([
            'email' => 'required|email',
            'password' => 'required',
            'device_name' => 'required',
        ]);

        $user = User::where('email', $request->email)->first();

        if (! $user || ! Hash::check($request->password, $user->password)) {
            throw ValidationException::withMessages([
                'email' => ['The provided credentials are incorrect.'],
            ]);
        }

        // Token with abilities (scopes)
        $token = $user->createToken(
            $request->device_name,
            ['read', 'write'] // Optional abilities
        );

        return response()->json([
            'token' => $token->plainTextToken,
            'expires_at' => null // Configure in sanctum.php
        ]);
    }

    public function revokeToken(Request $request)
    {
        // Revoke current token
        $request->user()->currentAccessToken()->delete();

        return response()->json(['message' => 'Token revoked']);
    }
}

auth:sanctumミドルウェアでルートを保護します。トークンの権限はtokenCanメソッドで確認できます。

routes/api.phpphp
use Illuminate\Support\Facades\Route;

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

    Route::post('/posts', function (Request $request) {
        // Check if token has write ability
        if (! $request->user()->tokenCan('write')) {
            abort(403, 'Token does not have write permissions');
        }

        // Create post logic
    });
});

Laravelの面接対策はできていますか?

インタラクティブなシミュレーター、flashcards、技術テストで練習しましょう。

Laravel Passportを使用すべき場面

Passportは、アプリケーションがOAuth2認可サーバーとして機能する必要がある場合に必要となります。主なユースケースは以下の通りです。

  • サードパーティ開発者がAPIとの連携を構築する場合
  • マイクロサービス間のマシン間認証
  • エンタープライズ顧客向けのOAuth2コンプライアンスが必要な場合
  • リフレッシュトークンローテーションとJWT検証が必要なシステム
app/Http/Controllers/Api/PassportController.phpphp
namespace App\Http\Controllers\Api;

use App\Models\User;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Hash;

class PassportController extends Controller
{
    public function issueToken(Request $request)
    {
        $request->validate([
            'email' => 'required|email',
            'password' => 'required',
        ]);

        $user = User::where('email', $request->email)->first();

        if (! $user || ! Hash::check($request->password, $user->password)) {
            return response()->json([
                'error' => 'invalid_credentials'
            ], 401);
        }

        // Create OAuth2 token with scopes
        $token = $user->createToken('API Token', ['read-posts', 'write-posts']);

        return response()->json([
            'access_token' => $token->accessToken,
            'token_type' => 'Bearer',
            'expires_at' => $token->token->expires_at
        ]);
    }
}

Passportはユーザーコンテキストなしのサーバー間認証のためのクライアントクレデンシャルグラントもサポートしています。

php
// Machine-to-machine authentication
// config/auth.php
'guards' => [
    'api' => [
        'driver' => 'passport',
        'provider' => 'users',
    ],
],

// routes/api.php - Client credentials protected route
Route::middleware('client')->group(function () {
    Route::get('/machine-data', function () {
        return response()->json(['data' => 'Machine accessible']);
    });
});

Laravel API認証のセキュリティベストプラクティス

両パッケージとも、基本設定以上のセキュリティ対策が必要です。トークンの有効期限、レート制限、適切なスコープ検証により、一般的な脆弱性を防止できます。

app/Providers/AuthServiceProvider.phpphp
namespace App\Providers;

use Illuminate\Support\ServiceProvider;
use Laravel\Sanctum\Sanctum;
use Laravel\Sanctum\PersonalAccessToken;

class AuthServiceProvider extends ServiceProvider
{
    public function boot(): void
    {
        // Set token expiration (Sanctum)
        Sanctum::authenticateAccessTokensUsing(function ($token, $isValid) {
            // Expire tokens after 24 hours
            $expiration = config('sanctum.expiration');
            
            if ($expiration === null) {
                return $isValid;
            }

            return $isValid && $token->created_at->gt(now()->subMinutes($expiration));
        });
    }
}

ブルートフォース攻撃を防止するため、認証エンドポイントにレート制限を実装します。Laravel 12はRateLimitingファサードを通じて柔軟なレートリミッター設定を提供します。

app/Providers/AppServiceProvider.phpphp
use Illuminate\Cache\RateLimiting\Limit;
use Illuminate\Support\Facades\RateLimiting;

public function boot(): void
{
    RateLimiting::for('login', function ($request) {
        return Limit::perMinute(5)->by($request->ip());
    });

    RateLimiting::for('api', function ($request) {
        return Limit::perMinute(60)->by($request->user()?->id ?: $request->ip());
    });
}

Laravel認証に関する面接質問

技術面接ではAPI認証パターンの理解がよく問われます。以下の質問はすべてのレベルのLaravel開発者面接で出題されます。

Q: SanctumのSPA認証とトークン認証の違いは何ですか?

SPA認証はCSRF保護付きのLaravelセッションCookieを使用します。フロントエンドが/sanctum/csrf-cookieを呼び出してセッションを確立し、以降のリクエストには自動的にセッションCookieが含まれます。トークン認証はAuthorizationヘッダーにBearerトークンを使用し、Cookieが実用的でないモバイルアプリやサードパーティ連携に適しています。

Q: SanctumではなくPassportを選択すべき場面はいつですか?

Passportは完全なOAuth2を実装しており、サードパーティ開発者が認可コードフローを使用してAPIと連携する必要がある場合、またはマシン間認証にクライアントクレデンシャルグラントが必要な場合に必要です。Sanctumはファーストパーティアプリケーションをよりシンプルに処理します。

Q: SanctumはAPIトークンをどのように保存しますか?

Sanctumは各トークンのSHA-256ハッシュをpersonal_access_tokensテーブルに保存します。平文トークンは作成時に一度だけ返されます。このアプローチにより、データベースが漏洩しても有効なトークンは露出しません。

Q: Sanctumでトークンのabilities(スコープ)を実装する方法は?

php
// Creating token with abilities
$token = $user->createToken('api-token', ['posts:read', 'posts:write']);

// Checking abilities in controller
if ($request->user()->tokenCan('posts:write')) {
    // Authorized for write operations
}

// Middleware-based ability check
Route::middleware(['auth:sanctum', 'ability:posts:write'])
    ->post('/posts', [PostController::class, 'store']);

Q: Sanctumでユーザーのすべてのトークンを無効化する方法は?

php
// Revoke all tokens
$user->tokens()->delete();

// Revoke specific token by ID
$user->tokens()->where('id', $tokenId)->delete();

// Revoke current token only
$request->user()->currentAccessToken()->delete();

PassportからSanctumへの移行

Passportで開始したものの、シンプルなトークン認証のみを使用しているアプリケーションは、複雑さを軽減するためにSanctumに移行できます。移行にはトークン作成、ミドルウェア設定、スコープチェックの更新が必要です。

php
// Migration helper: Convert Passport tokens to Sanctum
use App\Models\User;
use Laravel\Passport\Token;

// This is a one-way migration - run once then remove Passport
User::chunk(100, function ($users) {
    foreach ($users as $user) {
        $passportTokens = Token::where('user_id', $user->id)
            ->where('revoked', false)
            ->get();

        foreach ($passportTokens as $token) {
            $user->createToken(
                $token->name ?? 'migrated-token',
                $token->scopes ?? []
            );
        }
    }
});

ルートミドルウェアをauth:apiからauth:sanctumに更新し、$request->user()->token()->scopes$request->user()->currentAccessToken()->abilitiesに置き換えます。

まとめ

  • Sanctumは最小限の設定でSPA、モバイルアプリ、ファーストパーティAPIに適しています
  • PassportはOAuth2認可サーバーとサードパーティ連携を処理します
  • SPA認証はセッションCookieを使用し、API認証はBearerトークンを使用します
  • トークンのabilitiesはSanctumで細かい権限制御を提供します
  • レート制限とトークン有効期限は、パッケージ選択に関係なく必須のセキュリティ対策です
  • ほとんどのLaravelアプリケーションはSanctumから始め、OAuth2コンプライアンスが必要になった場合にのみPassportを追加すべきです

今すぐ練習を始めましょう!

面接シミュレーターと技術テストで知識をテストしましょう。

タグ

#laravel
#sanctum
#passport
#api-authentication
#oauth2

共有

関連記事