エッジケースっぽいのを踏んだので記録しておきます。
TL;DR
Keycloak 26.0.5 で、本体のテーマを継承してテーマを作成すると、AuthChecker.js の機構によって iPhone でのログイン処理が阻害されてしまうことが起きるようです。
すでに issue, PR も出されており、26.0.7 では解決されていると思われます
- issue: RESTART_AUTHENTICATION_ERROR in Iphone devices (using safari and chrome browser) #33071
- PR: Improve session polling to prevent accidental redirects #35143
また、この issue によれば 25.0.1 時点ではすでに発生していたようです。
対策としては PR が取り込まれている 26.0.7 まで update すればいいはずです
(base テーマの AuthChecker.js
がポイントになるので、この内容だけコピペして自前で用意している場合は最新の AuthChecker.js
の内容で再度上書きしてしまうのが良いと思います)
発生した環境
- Keycloak バージョン:26.0.5
- 不具合の発生を確認したデバイス:iPhone SE (第二世代)
- iOS バージョン: 17.7
発生した事象の概要
OIDC で連携しているクライアントアプリケーションがあります。
PC のブラウザからログインする際には特に問題なくログイン後、クライアントアプリケーションへリダイレクトが実行されて認証が完了する、ということができます。
一見問題はなさそうだったのですが、iPhone のブラウザからログインを行うと not found という画面に遷移してしまう、という問題がありました
issue, PR の発見
iPhone でインスペクターを利用したり、ログを調べたり、で調査したところ、どうやら iPhone 上でログインした際のエラーは RESTART_AUTHENTICATION_ERROR
というイベントで記録されているようでした。
type="RESTART_AUTHENTICATION_ERROR",
realmId="01760ed5-0ece-4a4d-b846-edbb69948fb2",
realmName="******",
clientId="="******",
userId="null",
ipAddress="******",
error="already_logged_in",
response_type="code",
redirect_uri="https://******/auth/******/callback",
redirected_to_client="true",
response_mode="query"
ログのイメージ
この情報を元に、公式 repository で issue が起票されているのを発見しました。
deepl 翻訳
iPhoneデバイス(SafariとChrome)でKeycloakを認証する際に問題が発生しています。
デスクトップブラウザ(WindowsのChrome)では認証フローは正しく動作しますが、iPhoneではプロセスが失敗し、期待した認証コードパラメータを受け取る代わりに認証が再開されるか、temporarily_unavailableエラーが表示されます。
まさしくこれっぽいです。修正版の提案もあります。
ですがタイムリーすぎてこの不具合を検知したタイミングでは、まだ修正版のリリースが行われていないようでした
26.0.7 には取り込まれているようなので、そこまでバージョンを上げてしまうのが得策です。
バージョンを上げられない場合は続きを参考にしてください
自分たちの管理するテーマで直接 AuthChecker.js
を書き換えて対応する
この不具合の調査をした当時、まだ最新のバージョンに不具合修正の PR が取り込まれておりませんでした。
ただし、 PR の内容を見ると、base テーマ上の変更だけに閉じており、上書き可能なテンプレートとしてのテーマであれば、手動で自分たちの運用するテーマで修正が可能なのではないか?と気付きました。
そんなわけで、以下を行うことで不具合を解消しました
- テーマの最新化
- 今まで取り込んでいた
AuthChecker.js
の呼び出し部分が古くなっていたため最新化
- 今まで取り込んでいた
- 修正版 PR の内容を先んじて取り込む
得られた学び
iPhone のデバッグはマジでむずい
- 参考にしたページ
- iPhone の端末を mac に繋げ、 mac 側の Safari を開いてインスペクタを起動する ことで element や network といった開発者ツールの機能を利用できる
- これは iPhone 側を chrome にすることで、chrome での表示のデバッグもできる
- ただし、 PC の chrome における開発者ツールほど使い勝手がよろしくない
認識していない処理がフロントで実行されていると、それを認識すること自体が難しい
-
AuthChecker.js
という仕組みが outdate していたこと、および独自拡張で用意した js と競合していたことが問題の中心 - 詳しく知らないが、既存の base template で参照している都合、使用しておいた方がよさそう、という固定観念があった
iPhone のようなケースまでフォローしながら update を行うのは難しそう
- 全ての端末と全てのブラウザでログインフローを確認するテストを用意するのは対策になりそう
- あるかどうかもわからない問題を拾いにいく、ためのテストなので労力に対して見返りが少ないのが難点
- 現状では腹を括るしかない、気がする
おまけ:悩み事
結構柔らかめの話を吐露しておきます
AuthChecker.js をどう活用すべきか
AuthChecker.js
が複数 tab にまたがって認証状態を管理しており、認証されたら自動的に特定の URL へ遷移させるという仕組みになっているようです。
どんな目的なのかを考えると、おそらく複数の tab で同じ ID のログイン画面を開いてしまった、という場合に何度もログイン作業を行うことがないようにしているのだと思われます。
確かにそういうケースはあるので方針は理解できるものの、これだと state の管理ができないのでおそらく一つの tab 以外はログインに失敗するはず(多分)
現在運用している Keycloak では、失敗しても一つの tab でログインできていれば違和感はないだろう、という気持ちでこの機構を残してはいるものの、そもそも勝手に画面遷移しない方がエンドユーザーにとって優しいのでは?という気持ちもあり、正直迷うところではあります・・・
テーマの更新への追従、どうすればいいのか
Keycloak のテーマはややこしい仕組みになっています。
まず base
, keycloak
, keycloak.v2
というそれぞれ公式によって事前に用意されたテンプレートとしてのテーマが存在します。
これを継承する形で拡張することが可能であり、自分の運用する Keycloak でも、 keycloak
テーマを parent
として作成しています。
parent=keycloak
import=common/keycloak
### 以下省略 ###
parent
の属性によって継承元を指定することで、特定のテーマを引き継ぎます。
継承先のテーマでは、同じ名前のファイルを作成することでオーバーライドが可能です。今回は、オーバーライドしてなかったことで引き当ててしまったことになります。
具体的には、keycloak テーマの AuthChecker.js
が更新されていることに気が付かなかった ことが遠因になっています。
じゃあ継承なしで完全に新規で作成しますと、それはそれでさらにバックエンドの仕組みと不整合が起きる可能性があり、これも微妙です
そういうわけで、一旦現状では、アップデートのたびにテーマに変更がないこと、を確認しに行くのがよさそうです。
(完全にできるかどうかは別として、ですが・・・原則としては多分そう・・・おそらく・・・)