2026年8月28日

2026年8月28日

Laravelの認証(Auth)機能の実装方法:SanctumでAPIトークン認証を作る

Laravel で API に認証を付けるなら、まず公式パッケージの Laravel Sanctum を検討するのが近道です。Sanctum を使うと、モバイルアプリや外部のスクリプト向けに API トークンを発行し、トークンごとに権限(アビリティ)と有効期限を付けて管理できます。この記事では、Sanctum の導入、トークンの発行と失効、権限の確認、有効期限と掃除、SPA の場合の選び方、本番で守りたいセキュリティの要点までを説明します。画面付きのログイン機能(スターターキットや Auth::attempt() を使う方法)は別記事で扱っているので、ここでは API の認証に絞ります。

Sanctum が向いている場面

Laravel の API 認証にはいくつかの選択肢があります。

  • Sanctum の API トークン: 自社のモバイルアプリ、社内ツール、外部のスクリプトなどに、ユーザーごとのトークンを発行する用途に向いています。
  • Sanctum の Cookie 認証(SPA 認証): 同じドメイン配下で動く自社の SPA(Vue や React の画面)から API を呼ぶ場合に使います。トークンを JavaScript で扱わずに済みます。
  • Laravel Passport: 自分のアプリを OAuth2 の認可サーバーにして、第三者のアプリに「このアプリに連携を許可しますか」という画面を出す必要がある場合に使います。
  • JWT: 外部の仕組みと連携する都合で JWT が必要な場合の選択肢です。トークンの失効を自分で設計する必要があり、扱いは難しくなります。

第三者向けの OAuth2 が不要なら、多くの場合 Sanctum で足ります。パッケージの機能や導入コマンドは Laravel の版で変わるため、公式ドキュメントの Sanctum のページで確認してください(2026年10月現在)。

導入

Laravel 11 以降では、次のコマンドで Sanctum の導入と API 用ルートファイル(routes/api.php)の作成が行われます。

php artisan install:api
php artisan migrate

マイグレーションで personal_access_tokens テーブルが作られ、ここに発行したトークンが保存されます。それより前の版では、composer require laravel/sanctum でパッケージを入れ、設定ファイルとマイグレーションを公開する手順になります。

次に、User モデルに HasApiTokens トレイトを追加します。

use Illuminate\Foundation\Auth\User as Authenticatable;
use Laravel\Sanctum\HasApiTokens;

class User extends Authenticatable
{
    use HasApiTokens;
    // 既存のトレイトや設定はそのまま残す
}

作業前に Git でコミットし、既存のプロジェクトに導入する場合はステージング環境で試してから本番に反映します。

トークンを発行する

メールアドレスとパスワードを受け取り、正しければトークンを返すエンドポイントを作ります。総当たりを防ぐため、先にレート制限を定義しておきます。

// app/Providers/AppServiceProvider.php の boot() 内
use Illuminate\Cache\RateLimiting\Limit;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\RateLimiter;
use Illuminate\Support\Str;

RateLimiter::for('token-issue', function (Request $request) {
    return Limit::perMinute(5)->by(
        Str::lower((string) $request->input('email')).'|'.$request->ip()
    );
});
// routes/api.php
use App\Models\User;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Hash;
use Illuminate\Support\Facades\Route;
use Illuminate\Validation\ValidationException;

Route::post('/tokens', function (Request $request) {
    $validated = $request->validate([
        'email' => ['required', 'string', 'email'],
        'password' => ['required', 'string'],
        'device_name' => ['required', 'string', 'max:100'],
    ]);

    $user = User::where('email', $validated['email'])->first();

    if (! $user || ! Hash::check($validated['password'], $user->password)) {
        throw ValidationException::withMessages([
            'email' => ['メールアドレスまたはパスワードが正しくありません。'],
        ]);
    }

    $token = $user->createToken(
        $validated['device_name'],
        ['posts:read'],          // このトークンに許可する権限
        now()->addDays(30)       // このトークンの有効期限
    );

    return response()->json(['token' => $token->plainTextToken]);
})->middleware('throttle:token-issue');

ここでのポイントは次のとおりです。

  • エラーメッセージを区別しない: 「アカウントが存在しない」と「パスワードが違う」を同じ文言にし、登録済みのメールアドレスを探られないようにします。
  • レート制限: メールアドレスと IP の組み合わせで1分あたりの試行回数を制限しています。上限を超えると 429 が返ります。
  • トークンは一度しか見えない: plainTextToken は発行時にだけ取得できます。データベースにはハッシュ化した値が保存されるため、後から元の文字列を確認することはできません。紛失したら再発行してもらう運用にします。
  • 最小限の権限で発行する: 第2引数に、そのトークンでできることを列挙します。読み取りだけのアプリに書き込み権限を渡さないようにします。

createToken() の第3引数で有効期限を指定する書き方は、比較的新しい版の Sanctum で使えるものです。古い版では使えないことがあるので、導入した版のドキュメントで確認してください。

トークンで API を呼ぶ

クライアントは、Authorization ヘッダーにトークンを付けて API を呼びます。

curl -H "Accept: application/json" \
     -H "Authorization: Bearer your-api-token" \
     https://example.com/api/me

Accept: application/json を付けておくと、認証に失敗したときにログイン画面へのリダイレクトではなく、401 の JSON が返ります。

保護したいルートには auth:sanctum ミドルウェアを付けます。

Route::middleware('auth:sanctum')->group(function () {
    Route::get('/me', function (Request $request) {
        return $request->user()->only(['id', 'name', 'email']);
    });

    Route::delete('/tokens/current', function (Request $request) {
        $request->user()->currentAccessToken()->delete();

        return response()->noContent();
    });
});

/me では、ユーザーモデルをそのまま返さず、必要な項目だけを返しています。モデルを丸ごと返すと、将来追加したカラムまで意図せず外部に出てしまうことがあります。

権限(アビリティ)を確認する

トークンに付けた権限は、コードの中で tokenCan() を使って確認できます。

if (! $request->user()->tokenCan('posts:write')) {
    abort(403);
}

ルート単位で確認したい場合は、Sanctum が提供するミドルウェアに別名を付けて使います。Laravel 11 以降では bootstrap/app.php で登録します。

use Laravel\Sanctum\Http\Middleware\CheckAbilities;
use Laravel\Sanctum\Http\Middleware\CheckForAnyAbility;

->withMiddleware(function ($middleware) {
    $middleware->alias([
        'abilities' => CheckAbilities::class,      // 列挙した権限をすべて持つ
        'ability' => CheckForAnyAbility::class,    // いずれか1つを持つ
    ]);
})
Route::post('/posts', [PostController::class, 'store'])
    ->middleware(['auth:sanctum', 'abilities:posts:write']);

トークンの権限は「このトークンに何を任せたか」を表すもので、「このユーザーがその投稿を編集してよいか」の判断とは別です。他人の投稿を編集できないようにする確認は、Policy や Gate で別途行います。両方を通ったときだけ処理する形にしてください。

有効期限と失効の運用

トークンの有効期限は、発行時に個別に指定するほか、config/sanctum.php の expiration(分単位)で全体の期限を決められます。null のままだと、期限のないトークンになります。長く使われるトークンほど漏えいしたときの影響が大きいので、用途に合わせて期限を設けます。

期限切れのトークンはテーブルに残り続けるため、定期的に削除します。Laravel 11 以降なら routes/console.php にスケジュールを書きます。

use Illuminate\Support\Facades\Schedule;

Schedule::command('sanctum:prune-expired --hours=24')->daily();

失効させたい場面も決めておきます。

  • ログアウト: 先ほどの /tokens/current のように、使っているトークンだけを削除します。
  • パスワード変更や不正利用の疑い: $user->tokens()->delete(); でそのユーザーのすべてのトークンを削除します。
  • 端末ごとの管理: personal_access_tokens には発行時の名前(ここでは device_name)と最終利用日時が残るので、ユーザー向けに「ログイン中の端末」の一覧と個別の削除機能を作ることもできます。

SPA ならトークンより Cookie 認証を検討する

自社の SPA から同じドメイン配下の API を呼ぶ場合、トークンを発行してブラウザの localStorage に保存する方式は避けたほうが安全です。XSS の脆弱性があると、スクリプトからトークンを読み取られるためです。Sanctum の SPA 認証では、通常のセッション Cookie で認証し、CSRF 対策も Laravel 側で行われます。

大まかな流れは、bootstrap/app.php で $middleware->statefulApi(); を有効にし、.env の SANCTUM_STATEFUL_DOMAINS に SPA のドメインを設定し、SPA からはまず /sanctum/csrf-cookie を呼んでからログインする、というものです。ドメインやサブドメインの構成、CORS の設定で動かないことが多いため、公式ドキュメントの手順に沿って確認してください。モバイルアプリでトークンを使う場合は、端末の安全な保存領域(iOS のキーチェーンや Android の Keystore など)に保存します。

本番運用のセキュリティチェック

  • HTTPS で配信する: トークンは Authorization ヘッダーで毎回送られるため、HTTP では盗聴されます。
  • ログにトークンやパスワードを残さない: リクエストヘッダーや入力値を丸ごとログに記録しないようにします。エラー監視サービスを使う場合も、送信される項目を確認します。
  • トークンをコードやリポジトリに書かない: テスト用のトークンも、環境変数や CI の秘密情報の機能で扱います。
  • 締め出されたときの復旧手段: レート制限の記録はキャッシュに保存されます。誤って自分がブロックされても、サーバーで php artisan cache:clear を実行すれば解除できます。トークンを紛失した場合は、管理者がサーバー上でユーザーのトークンを削除し、再発行してもらいます。
  • 個人情報の扱い: メールアドレスや端末名、最終利用日時は個人に結び付く情報です。保存する項目を必要最小限にし、利用目的をプライバシーポリシーに記載します。

まとめ

  • 第三者向けの OAuth2 が不要な API なら、Sanctum の API トークンが扱いやすい選択肢です。
  • トークンは発行時にだけ平文で見え、データベースにはハッシュが保存されます。最小限の権限と有効期限を付けて発行します。
  • 発行エンドポイントにはレート制限を付け、エラーメッセージでアカウントの有無を漏らさないようにします。
  • トークンの権限確認とは別に、Policy や Gate で操作の可否を確認します。
  • 自社の SPA にはトークンではなく Sanctum の Cookie 認証を検討し、期限切れトークンは定期的に削除します。

お気軽にご相談ください

お見積りへ お問い合わせへ
▲