yasudacloudの日記

札幌に住むソフトウェアエンジニア

Basic認証とBearer認証を同時に利用する

クラウド環境の構築を行なっていると、ごくたまにBasic認証とBearer認証の2つを行いたい時があります。

具体的にはWebAPIとフロントエンド(SPAやSSG等)が分離されている構成でBearerを使っているケースです。検証環境のような非公開のシステムにBasic認証をつい設定してしまうとAuthorizationヘッダーが競合します。

これに対する解決方法をいくつか挙げてみます。

1. Basic認証をやめる

いっそ止めるという方法。代わりにIP制限ではどうかと一考の余地あり。

2. ドメインをAPIとフロントエンドで異なるものにする

Basic認証をフロントエンドだけに設定してAPIはBearerに使うようにすれば競合しません。個人的にはCORS対応が億劫なのであまり好きではありませんが。。

3. AuthorizationヘッダーのBearerをやめる

今回はこちらの方式について少し詳しく触れようと思います。

 

本題)フロントエンドからAuthorization: Bearerをやめる

まずBasic認証はブラウザ仕様によってAuthorizationヘッダーを置き換えることは出来ないと思うのでBearerの方を変更します。

つまり、フロントエンドからWebAPIにリクエストを投げる際にAuthorizationを使うのをやめて違うヘッダー名にします。これを仮にX-Authorizationとします。

そしてWebAPI側もX-Authorizationに変更することができれば言うことは何もないのですが、世の中には要件は満たしたいが仕様は変えられないこともあります。つまり、絶対Authorizationヘッダーに値を入れてほしいというケースに対応したいのです。

構成例🤔

図にするとこんな感じになります。

要はBasic認証を突破した以降のヘッダーはもうAuthorization: Basicである必要がないので、Webサーバー側で書き換えてアプリケーションサーバーに到達する時にAuthorization: Bearerで受け取れるようにすれば良いのではという発想です。

サンプル

WebサーバーをNginx、後ろのアプリケーションサーバーをPHPのビルトインサーバーで検証しました。X-Authorizationだとややこしいのでx-tokenとします。

Nginxの設定ファイルをこのように設定しました。

gist.github.com

Basic認証のユーザーはこんな感じで適当に作ります。

sudo htpasswd -c /opt/homebrew/etc/nginx/.htpasswd demo
hogehoge

次にプロキシ先のトップページ(index.html)からWebAPI(/bearer.php)を叩きます。

gist.github.com

そしてbearer.phpでリクエストヘッダーを出力するようにしています。

結果

気になる結果ですが、ちゃんとBasic認証のポップアップが出ました。


そしてBasic認証突破後の/bearer.phpへのリクエスト(x-token: Bearerで送っている)が

上記のようにAuthorizationとして受け取ることができました。

そもそもそんなケースある?🤔

と思ったかもしれませんが、Strapi(ヘッドレスCMS)のユーザー認証でAuthorizationが使われていて変更しようがなかったので今回のような考えに至りました。

CMSなり外部のシステムを使っていると起こりうるお話ですね。

余談ですが

CloudFrontでも同様のことができます。

CloudFront関数ではBasic認証とヘッダーの書き換えの両方を同時にできるので、今回のようにWebサーバーの設定をいじらず楽です。