「419エラー」「Page Expired」はLaravelが独自に返すステータスで、多くの場合CSRFトークンとセッションの不整合が原因です。本記事では、@csrf不足・Ajaxのトークン未設定・APP_KEY不一致・SESSION_DOMAIN設定ミスなど原因別のチェックリストを用意し、それぞれの直し方をコード例付きで解説します。上から順に確認すれば、多くの場合は数分で原因を特定できます。
419エラーが出たらまず確認!チェックリスト
419エラーの原因を素早く特定するために、以下の順序で確認してください。
- Bladeフォームに
@csrfが記述されているか - AjaxリクエストにCSRFトークンがヘッダーとして含まれているか
- セッションの有効期限が切れていないか(長時間放置後に発生しやすい)
.envのAPP_KEYが正しく設定されているかSESSION_DOMAINとCOOKIE設定がドメインと一致しているか.envを変更した後にphp artisan config:clearを実行したか- ブラウザの「戻る」ボタンでキャッシュされた古いフォームを送信していないか
- 複数台のサーバーで運用している場合、セッションドライバがサーバー間で共有されているか
原因別チェック表
| 原因 | 確認箇所 | 対処方法 |
|---|---|---|
@csrf の不足 |
Bladeテンプレートのフォーム内 | <form> タグ直下に @csrf を追加 |
Ajax の X-CSRF-TOKEN 不足 |
fetch / axios のリクエストヘッダー | metaタグからトークンを取得してヘッダーに設定 |
| セッション期限切れ | config/session.php の lifetime |
セッション有効期間を延長、またはページをリロード |
APP_KEY の不一致 |
.env の APP_KEY |
php artisan key:generate で再生成 |
SESSION_DOMAIN / Cookie設定 |
.env の SESSION_DOMAIN |
ドメインに合わせた値を設定(例: .example.com) |
| フォームを長時間放置 | ブラウザ上での操作時間 | セッション期間を延長、またはAjaxで定期更新 |
| ブラウザの戻るボタン(bfcache) | フォーム送信後に「戻る」で古いページを再送信 | フォームページにCache-Control: no-storeを設定、またはpageshowイベントでリロード |
| 複数サーバーでのセッション不一致 | SESSION_DRIVER(fileのままロードバランサー配下) |
redisやdatabaseなど共有ストレージのセッションドライバに変更 |
419エラーとは?
419エラーはLaravel固有のHTTPステータスコードで、「Page Expired(ページの有効期限切れ)」を意味します。LaravelはCSRF攻撃を防ぐためにリクエストのCSRFトークンを検証しており、トークンが無効またはセッションが失効している場合にこのエラーを返します。
419エラーの主な原因と解決策
@csrf の不足(Bladeフォーム)
Laravelは web ミドルウェアグループにCSRF保護が含まれており、POSTリクエストにはCSRFトークンが必須です。Bladeテンプレートでは @csrf ディレクティブを使用してください。
<form method="POST" action="/submit">
@csrf
<!-- フォームフィールド -->
<button type="submit">送信</button>
</form>
Ajax / fetch / axios の X-CSRF-TOKEN 不足
JavaScriptからAjaxでリクエストを送る場合、CSRFトークンをリクエストヘッダーに含める必要があります。
HTMLにmetaタグを追加する
<meta name="csrf-token" content="{{ csrf_token() }}">
fetch を使った例
const token = document.querySelector('meta[name="csrf-token"]').getAttribute('content');
fetch('/api/submit', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'X-CSRF-TOKEN': token,
},
body: JSON.stringify({ name: 'value' }),
});
axios を使った例(グローバル設定)
import axios from 'axios';
axios.defaults.headers.common['X-CSRF-TOKEN'] =
document.querySelector('meta[name="csrf-token"]').getAttribute('content');
// 以降のすべてのPOSTリクエストに自動でヘッダーが付与される
axios.post('/api/submit', { name: 'value' });
セッション期限切れ
ユーザーがフォームを長時間開いたままにしていると、セッションが期限切れになって419エラーが発生します。config/session.php でセッションの有効期間を延長できます。
'lifetime' => 120, // セッションの有効期間(分)
長時間操作が必要なフォームでは、JavaScriptで定期的にサーバーへリクエストを送ってセッションを維持する方法も有効です。
APP_KEY の不一致
.env の APP_KEY はセッションの暗号化に使用されます。サーバー移行や環境コピー後にキーが変わると419エラーが発生します。
php artisan key:generate
実行後は必ずキャッシュをクリアしてください。
php artisan config:clear
php artisan cache:clear
SESSION_DOMAIN / Cookie設定
サブドメインをまたいで動作するアプリや、本番環境でCookieのドメイン設定が正しくないと419エラーになることがあります。.env を確認してください。
SESSION_DOMAIN=.example.com
SESSION_SECURE_COOKIE=true
ミドルウェア設定の確認
APIルートにCSRF保護が誤って適用されている場合、または逆にWebルートでCSRF保護が外れている場合にも問題が発生します。routes/web.php と routes/api.php の振り分けを確認してください。
// routes/web.php(CSRFトークンが必要なルート)
Route::middleware('web')->group(function () {
Route::post('/submit', [FormController::class, 'store']);
});
ブラウザの「戻る」ボタンで再送信されるケース(bfcache)
フォームを送信した後に「戻る」ボタンでフォームページに戻り、ブラウザのキャッシュ(bfcache)に残った古いページのまま再送信すると、CSRFトークンが既に無効になっており419エラーが発生します。これはLaravel側の不具合ではなく、ブラウザの仕様による挙動です。フォームページのレスポンスヘッダーでキャッシュを無効化するか、pageshowイベントでページ復元を検知してリロードすることで回避できます。
window.addEventListener('pageshow', function (event) {
if (event.persisted) {
// bfcacheから復元された場合はリロードして最新のCSRFトークンを取得
window.location.reload();
}
});
複数サーバー・ロードバランサー環境での419
複数台のWebサーバーで運用している場合、SESSION_DRIVER=fileのままだとセッションが各サーバーのローカルディスクに保存され、リクエストのたびに別サーバーへ振り分けられるとセッションが見つからず419エラーになります。ロードバランサー配下ではredisやdatabaseなど、サーバー間で共有できるセッションドライバを使用してください。
# .env
SESSION_DRIVER=redis
.env 設定変更後の注意点
APP_KEY や SESSION_DRIVER など .env を変更した後は、必ず設定キャッシュをクリアしてください。クリアしないと変更が反映されず419エラーが続きます。
php artisan config:clear
本番環境では php artisan config:cache で再キャッシュすることで設定読み込みが高速化されます。
php artisan config:cache
よくある質問(FAQ)
Laravelの419エラーとは?
419エラーはLaravel独自のHTTPステータスコードで、「Page Expired」とも呼ばれます。CSRFトークンの検証に失敗したとき、またはセッションが無効になったときにLaravelが返すエラーです。セキュリティ上の理由から不正なリクエストを拒否するための仕組みで、標準のHTTP仕様には存在しないLaravel特有のコードです。
419 Page Expiredを直すには?
最初に確認すべきはCSRFトークンの設定です。Bladeフォームでは @csrf を追加し、AjaxリクエストではヘッダーにCSRFトークンを設定します。それでも解消しない場合は、セッション設定・APP_KEY・SESSION_DOMAIN の順に確認し、.env 変更後は php artisan config:clear を忘れずに実行してください。
Ajaxで419になる原因は?
AjaxリクエストでCSRFトークンが送信されていないことが主な原因です。HTMLの <head> 内に <meta name="csrf-token" content="{{ csrf_token() }}"> を追加し、fetch であれば X-CSRF-TOKEN ヘッダーに、axios であれば axios.defaults.headers.common['X-CSRF-TOKEN'] にトークンの値を設定してください。
「戻る」ボタンを押したときだけ419になるのはなぜ?
ブラウザのbfcache(back-forward cache)に残っていた古いフォームページを再送信していることが原因です。Laravel側の問題ではなくブラウザの挙動によるものなので、フォームページでpageshowイベントを監視してページ復元時にリロードするか、フォームページのキャッシュを無効化することで解消できます。
ロードバランサー配下だけで419が頻発するのはなぜ?
SESSION_DRIVER=fileのまま複数サーバーで運用していると、リクエストのたびに振り分け先サーバーが変わり、セッションファイルが見つからず419になります。redisやdatabaseなどサーバー間で共有できるセッションドライバに変更してください。
関連記事
- Laravelの419 Page Expiredエラーを解決する実践ガイド|CSRF・セッション原因別の対処法とコード例(コピペで試せる手順を原因別にさらに詳しく解説)
- LaravelのAPP_KEYを安全に生成・管理する方法とその重要性
- php artisan key:generateの使い方|APP_KEY生成コマンドの構文と注意点
- Laravelでの422エラーハンドリング: 原因と効果的な解決方法
まとめ
419エラーは冒頭のチェックリスト順に確認すれば、ほとんどのケースで原因を特定できます。Bladeフォームの @csrf 忘れやAjaxのヘッダー設定漏れが最も多い原因です。.env を変更したときは php artisan config:clear を必ず実行し、セッション設定や APP_KEY も合わせて確認することで、419エラーを確実に解消できます。

コメント