別ドメインへの302 redirectを返す別ドメインのAPIを呼び出すとCORSエラーが発生することがわかった。

説明が難しいのだが、自分の具体的なケースを書くと、

  • ドメインA(フロントエンドサーバ)からドメインB(バックエンドAPIサーバ)のAPIを呼び出す
  • APIがGoogle OAuth認証のためにドメインC(account.google.com)への302 Redirectを返す
  • CORSエラー発生

という流れで、以下のエラーが発生した。

Access to XMLHttpRequest at 'https://accounts.google.com/o/oauth2/auth?client_id=**********.apps.googleusercontent.com&redirect_uri=http%3A%2F%2Flocalhost%3A8080%2Flogin&scope=profile&state=**********&response_type=code&response_mode=query' (redirected from 'http://localhost:8080/hoge') from origin 'null' has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource.

エラー発生のメカニズム

処理の流れは以下のような感じ。諸悪の根源はブラウザがドメインCにリダイレクトする際にOrigin: nullヘッダーを設定することのようだ。

  1. ドメインAからドメインBのAPIをrequestする
  2. ドメインBは、Access-Control-Allow-Origin: *を設定したうえで、LocationにドメインCのURLを指定してresponseを返す
  3. 全てのOriginが許可されているためCORSエラーは発生しない
  4. ブラウザは、ドメインCにリダイレクトする。この際、Origin: nullヘッダーが設定される
  5. ドメインCは、Access-Control-Allow-Originヘッダーをつけずに、responseを返す
  6. ブラウザは、冒頭に書いたCORSエラーを発生させる

<シーケンス図>

この問題に対する回避方法は見つからなかった

結論、Issueは発見するものの対応方法まで言及されているものはなかった。

対応案1:ドメインを統一する -> 結局解決しなかった

ドメインAとドメインBがCross Originの状態でリダイレクト時にOrigin: nullヘッダーをつけないようにすることはできなそうなので、ドメインAとドメインBのドメインを一致させることにした。詳細は別記事を書いたのでそちらを参照のこと。
ローカル環境で開発中の複数アプリサーバのドメインをNginxで統一する

しかし、結果として問題は解決しなかった。リバースプロキシを立てることで、ドメインを統一することはできたものの、以下のエラーが引き続き発生したのである。

Access to XMLHttpRequest at 'https://accounts.google.com/o/oauth2/auth?client_id=**********.apps.googleusercontent.com&redirect_uri=http%3A%2F%2Frinoguchi.io%2Flogin&scope=profile&state=**********&response_type=code&response_mode=query' (redirected from 'http://rinoguchi.io/hoge') from origin 'http://rinoguchi.io' has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource.

理由としては、 ドメインが一致したらリダイレクト時にOriginヘッダーをつけなくなるのだと思っていたが、Origin: http://rinoguchi.ioが設定されているためのようだ。
Google APIの設定で承認済みドメインにrinoguchi.ioを追加してみたのだが、Access-Control-Allow-Originを設定してくれることもなく影響はなかった。

対応案2:別ドメインへの302 Redirectをやめる -> これで解決

色々調べていると、どうやら別ドメインへ302 RedirectをするとAllow-Originを設定しない限りは、CROSエラーにされてしまうようだった。なので、とても面倒だったが、302リダイレクトを行わない形に処理を組み替えることにした。詳細は別記事を書いたので、こちらを参照のこと。
Ktorで構築したAPIサーバのGoogle OAuth認証処理の全体像

この対応により、やっとCORSエラーを起こさずGoogle OAuth認証を行うことができる様になった。