別ドメインへの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
ヘッダーを設定することのようだ。
- ドメインAからドメインBのAPIをrequestする
- ドメインBは、
Access-Control-Allow-Origin: *
を設定したうえで、LocationにドメインCのURLを指定してresponseを返す - 全てのOriginが許可されているためCORSエラーは発生しない
- ブラウザは、ドメインCにリダイレクトする。この際、
Origin: null
ヘッダーが設定される - ドメインCは、
Access-Control-Allow-Origin
ヘッダーをつけずに、responseを返す - ブラウザは、冒頭に書いたCORSエラーを発生させる
<シーケンス図>
この問題に対する回避方法は見つからなかった
結論、Issueは発見するものの対応方法まで言及されているものはなかった。
- https://stackoverflow.com/questions/51743710/origin-null-is-therefore-not-allowed-access
- https://stackoverflow.com/questions/30193851/ajax-call-following-302-redirect-sets-origin-to-null
- https://stackoverflow.com/questions/25499169/why-does-my-redirected-cors-request-fail
- https://w3c.github.io/webappsec-cors-for-developers/#avoid-returning-access-control-allow-origin-null
対応案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認証を行うことができる様になった。