LaravelでAPI認証を実装する方法(Sanctum)
- 作成日 2026.03.19
- その他
Laravel Sanctumは、LaravelでAPI認証を実装するときに最も扱いやすい選択肢の1つ。特に、自社のSPA、モバイルアプリ、社内ツール、シンプルな外部連携APIのように、OAuth2の大掛かりな仕組みまでは不要だが、確実にAPIを保護したい場面で強い。実務では「ログイン後にトークンを発行してAPIを叩く方式」と、「SPAがCookieベースで認証される方式」の2系統を整理しておくと設計がぶれにくい。この記事では、Sanctumを使ったAPI認証の導入、トークン発行、保護ルート、権限制御、失効処理、よくあるエラーまでを一通り整理する。
Sanctumが向いているケース
Sanctumが向いているのは次のような構成。
・自社のフロントエンドとLaravel APIを接続したい
・モバイルアプリ向けにトークン認証を用意したい
・ユーザー単位で複数トークンを管理したい
・OAuth2の認可コードフローまでは不要
・まずは軽量で実装しやすいAPI認証を採用したい
逆に、第三者アプリ向けの本格的なOAuth2認可サーバーが必要なら、SanctumよりPassportの方が適している。
Sanctumの認証方式は2種類ある
Sanctumには大きく2つの使い方がある。
1つ目は、Bearerトークンを発行して Authorization: Bearer ... で認証する方式。
2つ目は、SPAがLaravelのセッションCookieを使って認証される方式。
この2つは同じSanctumでも動き方がかなり違うため、最初に「トークン方式でいくのか」「SPA Cookie方式でいくのか」を決めておく必要がある。
モバイルアプリやシンプルな外部クライアントならトークン方式、同一組織のSPAならCookie方式が扱いやすい。
導入の基本手順
LaravelのAPIルートとSanctumの基盤を整えるには、まずAPIインストールを実行する。
これにより、API認証に必要な土台が入り、routes/api.php も用意される。
php artisan install:api
プロジェクトによっては、すでにAPIルートが存在することもあるが、その場合でもSanctumを使う前提でルートと認証方式を整理した方が安全。
発生しやすい問題は、
・APIルートが無い
・Sanctum前提で進めているのに install が未実行
・既存構成と新規構成が混ざって認証ガードが分からなくなる
といったもの。
Userモデルの準備
Sanctumでトークンを発行するには、認証対象のモデルに HasApiTokens トレイトを追加する。通常は User モデルに付ける。
namespace App\Models;
use Illuminate\Foundation\Auth\User as Authenticatable;
use Laravel\Sanctum\HasApiTokens;
class User extends Authenticatable
{
use HasApiTokens;
// ...
}
これを入れておくことで、ユーザーから createToken() を呼べるようになる。
発生しやすいエラー条件は、
・HasApiTokens を付け忘れて createToken() が呼べない
・認証対象が User 以外なのに、そのモデル側設定をしていない
というもの。
ログイン処理でトークンを発行する
Sanctumのトークン認証では、ログイン成功後にトークンを発行して返すのが基本になる。
以下はシンプルな例。
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Hash;
use App\Models\User;
public function login(Request $request)
{
$request->validate([
‘email’ => [‘required’, ‘email’],
‘password’ => [‘required’, ‘string’],
]);
$user = User::where('email', $request->email)->first();
if (! $user || ! Hash::check($request->password, $user->password)) {
return response()->json([
'message' => '認証情報が正しくありません。'
], 422);
}
$token = $user->createToken('api-token')->plainTextToken;
return response()->json([
'token' => $token,
'user' => $user,
]);
}
この実装でよくある問題は、
・ログインは成功しているのにトークンを返していない
・トークンは返しているが、クライアントが保存していない
・パスワード照合ではなく平文比較をしている
など。
保護したいルートにauth:sanctumを付ける
トークンを発行しただけでは意味がなく、認証が必要なルートを auth:sanctum で保護する必要がある。
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Route;
Route::middleware(‘auth:sanctum’)->get(‘/user’, function (Request $request) {
return $request->user();
});
複数ルートをまとめて保護するならグループ化すると分かりやすい。
Route::middleware(‘auth:sanctum’)->group(function () {
Route::get(‘/user’, function (Request $request) {
return $request->user();
});
Route::get('/orders', [OrderController::class, 'index']);
Route::post('/orders', [OrderController::class, 'store']);
});
発生しやすい問題は、
・ミドルウェアを付け忘れて認証無しでアクセスできてしまう
・全部のルートに付けてしまい公開APIまで401になる
・auth:api と auth:sanctum を混同する
というもの。
クライアントからBearerトークンでアクセスする
発行したトークンは、API呼び出し時に Authorization ヘッダで送る。
curl -X GET http://localhost/api/user \
-H “Accept: application/json” \
-H “Authorization: Bearer YOUR_TOKEN”
JavaScriptで送るなら次のような形になる。
fetch(‘/api/user’, {
method: ‘GET’,
headers: {
‘Accept’: ‘application/json’,
‘Authorization’: ‘Bearer YOUR_TOKEN’
}
});
ここでのエラー発生条件はかなり多い。
・Bearer を付けずにトークン文字列だけ送っている
・Authorization ヘッダ自体を送っていない
・古いトークンや失効済みトークンを使っている
・フロントでトークン保存先が不安定
という問題が起きやすい。
トークンごとに権限を分ける(abilities)
Sanctumでは、トークンごとに abilities を持たせることができる。
これは「読み取り専用トークン」「管理操作可能トークン」のように、トークン単位で権限を分けたいときに便利。
$token = $user->createToken(‘report-token’, [‘reports:read’])->plainTextToken;
チェックは次のように行う。
if (! $request->user()->tokenCan(‘reports:read’)) {
abort(403, ‘このトークンでは参照できません。’);
}
発生しやすい問題は、
・abilities を付けていないのに tokenCan() で制御しようとする
・何でもフル権限で発行してしまい、権限設計が意味を失う
というケース。
実務では、トークンに役割を持たせる設計にすると管理しやすい。
トークンの一覧管理と削除
ユーザーが複数端末から利用する場合、トークンを一覧管理できると便利。
Sanctumでは、ユーザーが持っているトークンを取得して削除できる。
// 全トークン取得
$tokens = $request->user()->tokens;
// 現在使っているトークンだけ削除
$request->user()->currentAccessToken()->delete();
// 全トークン削除
$request->user()->tokens()->delete();
ログアウト時に現在トークンだけ削除するのか、全端末分を削除するのかは、要件によって決める必要がある。
発生しやすい問題は、
・ログアウトしてもトークンが残り続ける
・不要な古いトークンが大量に残る
・どの端末用トークンか分からなくなる
という運用面の問題。
SPAで使う場合の考え方
SanctumはSPAのCookie認証にも対応している。ただし、これはBearerトークン方式とは別物。
SPA認証で必要になるのは、
・statefulドメイン設定
・CSRF Cookieの取得
・セッションクッキー送信
・CORS/withCredentials の整合
など。
そのため、SPA認証をやる場合は「トークン認証の記事」と完全に同じ流れでは進まない。
フロントが別ドメインにあるのか、同一ドメインなのかで設定も変わるため、最初に構成を固定する必要がある。
Sanctumだけでは認証UIは作られない
SanctumはAPIトークンと認証状態を扱う仕組みであって、ログイン画面、会員登録、パスワードリセット画面などを自動生成するものではない。
つまり、次のような機能は別途作る必要がある。
・ログインフォーム
・登録API
・パスワード再設定
・メール認証
必要なら Fortify や Starter Kit を併用する構成も現実的になる。
よくあるエラーと発生条件
Sanctum導入時によく起きる問題をまとめると次の通り。
・401 Unauthorized
発生条件:Bearer未送信、トークン不正、失効済み、auth:sanctum 未設定
・419 Page Expired
発生条件:SPAでCSRF Cookie取得不足、Cookie認証周りの不整合
・Call to undefined method createToken()
発生条件:HasApiTokens 未追加
・本番だけ認証できない
発生条件:Cookieドメイン、HTTPS、SameSite、stateful設定不整合
・abilities が効かない
発生条件:付与していない、使い方が曖昧
これらはほとんどがSanctum本体の問題ではなく、「認証方式の選択ミス」か「設定不整合」で起きる。
まとめ
LaravelでAPI認証を実装する際、Sanctumは非常に現実的で扱いやすい選択肢になる。
特に、
・シンプルなBearerトークン認証
・SPA向けCookie認証
・トークンごとの権限制御
を1つの仕組みでまとめやすい点が強い。
導入時は、
・トークン方式かSPA方式かを先に決める
・HasApiTokens を入れる
・ログイン時に createToken() で発行する
・auth:sanctum で保護する
・不要トークンを削除・管理する
という流れで組むと整理しやすい。
OAuth2ほど大掛かりな認可基盤が不要であれば、SanctumはLaravelで最初に検討すべきAPI認証手段になりやすい。
-
前の記事
LaravelでN+1問題を解決する方法 2026.03.18
-
次の記事
記事がありません
コメントを書く