🔐

VercelのMiddlewareを使って非Next.jsプロジェクトにBasic認証をかける

2022/08/03に公開2

プロトタイピングしたツールを、身内へ気軽に公開したくなることってありますよね。Cloudflare Accessみたいなちゃんとしたソリューションをイチから導入するほどのモチベーションはなくて、Basic 認証が付いてればまあいっか、くらいの気軽さのやつです。

近頃だと、筆者はフロントエンドプロジェクトを Vercel にデプロイすることが多いので、Vercel について調べてみました。

Vercel には、主に Next.js から使うことを前提とした、Edge Middleware という仕組みがあります。これはページの表示前に割り込む形で通信結果に介入できるので、Basic 認証を実装できそうです。

https://zenn.dev/a_da_chi/articles/52bc6954f95191

Next.js を使う場合はこれでいいのですが、目的次第ではCreate React AppViteのような、小さめのツールチェインでプロトタイピングをしたいケースもありますよね。そういった場合にも Edge Middleware で Basic 認証を使えると嬉しそうです。

幸いなことに、ドキュメントを読むと Next.js を使わない方法も解説されていました。

Next.jsを使わない方法もある

ベータ版とのことなので、前述の Next.js 向けの API と同じく今後は変更が入る可能性もありますが、ひとまずこれを使ってみましょう。

Next.js 向けの実装との違い

Next.js 版を参考にして、非 Next.js 向けの Edge Middleware を実装していきます。Next.js 向けの最新版と比べると一つ古い API で提供されているようなので、参考にする記事もひとつ前のものにします。

https://zenn.dev/a_da_chi/articles/2b94160f11671e

また、前述した公式ドキュメントの quickstart では "Vercel CLI" のタブを参考にして進めます。

https://vercel.com/docs/concepts/functions/edge-middleware/quickstart

1. トップレベルに middleware.js を設置する

まずは、プロジェクトのトップレベルに middleware.js というファイルを設置します。Vercel のビルドプロセスはこの名前のファイルがあると Edge Middleware の実装ファイルとして読み込もうとします。

ひとまず、前述の記事のサンプルコードをコピペしておいてください。(import 文は Next.js に依存しているので消していいです)

2. @vercel/edge をインストールして next() を置き換える

Next.js 向けの実装では NextResponse.next() となっている部分が非 Next.js プロジェクトでは利用できないので、代わりになる実装を用意します。 @vercel/edge にそれっぽい実装が生えているようです。

https://github.com/vercel/vercel/blob/68eb1971128ebb027de0812a2e92f259027ce37f/packages/edge/src/middleware-helpers.ts#L24-L34

これは使わせてもらいましょう。 @vercel/edge をインストールします。

$ npm install @vercel/edge

インストールしたら、 middleware.js でインポートしておきます。

middleware.js
import { next } from "@vercel/edge";

Edge Middleware は ES Modules 対応なので、普通に import 文を使って OK です。

import したら、 NextResponse.next() を置き換えます。

- return NextResponse.next();
+ return next();

これで OK です。

3. Buffer を atob に置き換え

さて、これで動くかなと思いきや、動かしてみるとエラーが出ます。 Buffer がないようです。

Edge Middleware のランタイムで使用できる API を確認してみましょう。

https://edge-runtime.vercel.app/features/available-apis

残念ながら Buffer は生えていないようですが、今回は Basic 認証の Base 64 デコードを行いたいだけなので、 atob 関数があれば事足りそうです。

- const [user, password] = Buffer.from(basicAuth, 'base64').toString().split(':')
+ const [user, password] = atob(basicAuth).toString().split(":");

これでできました!

全体像

最終的に、次のようなコードになりました。

middleware.js
import { next } from "@vercel/edge";

export const config = {
  matcher: "/",
};

export default function middleware(request) {
  const authorizationHeader = request.headers.get("authorization");

  if (authorizationHeader) {
    const basicAuth = authorizationHeader.split(" ")[1];
    const [user, password] = atob(basicAuth).toString().split(":");

    if (user === process.env.BASIC_AUTH_USER && password === process.env.BASIC_AUTH_PASSWORD) {
      return next();
    }
  }

  return new Response("Basic Auth required", {
    status: 401,
    headers: {
      "WWW-Authenticate": 'Basic realm="Secure Area"',
    },
  });
}

このコードを動かすために必要な準備は、次の 3 つです。

  1. プロジェクトのトップレベルに上記の middleware.js を設置する
  2. @vercel/edge をインストールする
  3. Vercel の環境変数に BASIC_AUTH_USERBASIC_AUTH_PASSWORD を設定する

あとは通常の Vercel のデプロイを行えば、Edge Middleware が動き始めます。

まとめ

Next.js を使わなくても Edge Middleware を利用できるのは地味に嬉しいですね。

ちょっとしたアプリケーションでも Next.js を使ってしまいがちではありますが、こういった小技が使える様になれば、Vite 等も選択しやすくなりそうです。

宣伝

株式会社モニクルでは、はたらく世代・子育て世代がお金の不安を手放せる手助けをするための金融サービス業をより広めるために、ソフトウェアエンジニアを募集しています。

90 秒だけお時間をいただいて、↓ の動画を見ていただけると、どんなサービスをやっている会社なのかざっくりわかってもらえると思います。

https://www.youtube.com/watch?v=mwZ_tnGKEIY

マネイロにお金の相談をしにきてくださるだけでも嬉しいですし、もしこの記事を読んで会社自体にも興味を持っていただけたら、↓ の Culture Deck(会社説明資料)を読んでみてください。

https://speakerdeck.com/monicle/about

さらに興味を持ってもらえた方は Meety で私と雑談しましょう!

https://meety.net/matches/egOQbaoKmgHd

よろしくお願いします!

株式会社モニクル

Discussion

ShumpeiShumpei

viteプロジェクトでも動作できるよう実装できました!
ありがとうございました