経緯
うぃすきー(@whisky_shusuky)です。
2022年10月頃にiOS16.1においてfirebase authenticationのリダイレクトを使ったサインインができない事象が発生しました。
発生直後のアプリリリースでは、
- OS側のアップデートが原因である
- 他のデバイスやブラウザでログイン操作が可能である(SYNMNはRFC8628に則って実装しているため)
ということでAppleの審査を通すことが出来ました。
しかし、その次のリリースでは審査が通らず対応が必要となったため、急遽クロ(@kro96_xr)と対応しました。
その際に何をやったかここに記録をここに記そうと思います。
調査と失敗
firebase側から、いくつかの対応案が出ていました。
対応オプション
- Firebase 構成を更新して、カスタム ドメインをauthDomainとして使用する
- signInWithPopup() に切り替える
- 認証リクエストを firebaseapp.com にプロキシする
- ドメインでサインイン ヘルパー コードを自己ホストする
- プロバイダーのサインインを個別に処理する
このうち、
- Firebaseにサービスをホストしていないのでオプション1はNG
- WebViewに対応しておきたいのでオプション2はNG
- Appleサインインを使うのでオプション4はNG
ということでオプション3かオプション5で対応することになりました。
オプション5は実装に時間がかかりそう、かつFirebase Authを使う意味があまりなくなるということで、今回はオプション3を選択しました。
オプション3の説明を見るとこのように書いてありました。
302 リダイレクト経由では実行できません。
じゃあ301でリダイレクトさせるか!
そう考えてサインインに関するアクセスをALBでhttps://<project>.firebaseapp.com
にリダイレクトさせて対応しましたが失敗しました...
よく読んでみる
よく文言を読むと以下のように記載してありました。
この転送がブラウザに対して透過的であることを確認してください。
「透過的って何だ?」となんとなく怪しい気持ちがして原文に当たると以下のように記載してありました。
Ensure that this forwarding is transparent to the browser
transparent
と書いてありました。そこで色々と調べたら Transparent Proxy(透過型プロキシ)という単語がヒットしたりしました。
よく考えたらnginxのプロパティが書いてあるしタイトルにもプロキシすると記載してあります。 そこでブラウザ上でリダイレクトさせるのではなくてnginxなどを使ってプロキシサーバーを立てろということなのではないかという仮説を立てました。 これが結果的に当たりでした。
プロキシを立てて対処
いい感じに簡単にproxyサーバーを立てられるawsのマネージドサービスが無いか探しましたが見つかりませんでした。
そのためFargateを元々APIサーバーに使っていたのでそこにnginxを立てられないか試しました。
まずは以下のような構成でレポジトリを切ってプロキシサーバのコードを用意しました
. ├─ Dockerfile └─ reverse-proxy/ ├── index.html └── nginx.conf
- Dockerfile
- ヘルスチェック用のindex.htmlとnginx.confを読み込む
FROM nginx:alpine COPY reverse-proxy/index.html /etc/nginx/html/index.html COPY reverse-proxy/nginx.conf /etc/nginx/nginx.conf
- index.html
- ヘルスチェック用なのでOKだけ返す
<html> OK </html>
- nginx.conf
- 実際はproxy_passの部分にfirebaseのプロジェクトを記載したパスを設定してリダイレクトするようにする。
events { worker_connections 16; } http { server { listen 80; server_name localhost; location / { index index.html; } location /__/auth { proxy_pass https://<project>.firebaseapp.com; } } }
こちらをecrにpushしてfargateの起動イメージに設定してproxyサーバーを立てました。 またFargateの前段にALBを立てていたのでそちらのルールを設定してサインイン用パスが叩かれた場合proxyサーバーに転送されるようにしました。
するとうまく動作してサインインに成功するようになりました。
終わり
ブラウザの仕様変更に振り回されましたが何とか解決できました。今回の教訓としては以下のようなことが挙げられると思います。運営していれば障害はつきものなので今後に活かしたいと思います。
- ドキュメントの日本語が怪しかったら原文を当たってみる
- 障害時は仮説を立てたらサッサと手を動かして検証する
- プロキシを立てるのが正解だったが立て始めた時点では不明だった
- 結果的に手を動かしてから2時間程度で解決した
参考リンク
同様の事象に別アプローチ(オプション5)で対応されている記事です。
Firebase AuthenticationのSafari 16.1で動作しなくなる問題の解決過程 - ぱいぱいにっき