📝

【Laravel】@csrfディレクティブがあるのに419エラーが発生する【Android Chrome】

2023/09/21に公開

概要

作成した Web アプリケーションを様々な OS やブラウザで検証していたところ、ログインフォームにて 419 エラーが発生しました。
しかも Android の Chrome のみで発生し、Windows10 や macOS の Chrome では発生しませんでした。
結果的にアプリケーション側の不具合ではなかったのですが、原因の究明に時間がかかってしまったため忘備録としてまとめます。

原因

以下の動作を行っていたため

  1. パスワードマネージャが表示するユーザー情報を選択(1度目の submit)
  2. すぐにログインボタンの押下(2度目の submit)

この2回目の submit が起きるせいで 419 エラーが発生する。

解説

Laravel で 419 エラーが発生した際の対処法としては「blade の form 内に@csrf ディレクティブを付与する」という記事が山ほど出てきます。
しかし今回の事象として、

  • @csrf ディレクティブ書いてる
  • Android の Chrome のみ、他は問題なし

という条件だったため、原因の究明に苦労しました。

そんな中 Laracasts で同様事象の質問を発見し、以下の解答を発見しました。

Guys, I have the answer! (to my 419 error)
The core issue is that Google Chrome on mobile now automatically tries to submit the "Log In" form for you when using its password manager. [1]
So, if you are like me, you are inadvertently submitting the form twice..
First, when you select your password (per [1])
Second, when you click the "Log In" button
The second click is what causes the 419 error, and is why a simple refresh, after you see the 419 error, indicates that you are logged in.
This behavior isn't really Laravel's fault, but it is so annoying and pernicious, it should probably be addressed in the core.

よって以下の結論に至りました。

最近のブラウザでは、一度ログインすると認証情報をパスワードマネージャに保存することが当たり前になっています。

Android の Chrome でも当然可能なのですが、ログイン時に表示されたユーザーを選択(タップ)した時点で submit される仕様になっています。
つまりその後すぐにログインボタンを押下すると2度目の submit が発生してしまい、1度目のリクエストで使用した期限切れのトークンが送信されてしまうことで 419 エラーとなります。

よって動作確認時は、

  • パスワードマネージャのユーザー情報をタップしたらおとなしく待つ
  • 手入力する

のどちらかでなければならない、という結論に至りました。

まとめ

結果的にアプリケーション側の不具合ではなくホッとしましたが、動作検証時も細かいブラウザ仕様の差異を認識しておく必要があることを改めて感じました。

参考

https://laracasts.com/discuss/channels/laravel/419-login-link-expired-errors-on-mobile-only?page=1&replyId=867897

GitHubで編集を提案

Discussion