🧐

【Next.js】Middlewareを用いたBasic認証の実装方法

に公開

きっかけ

アウトプットを兼ねてアプリを作成していて、Next.jsを使用していたので手っ取り早くという観点でVercelにデプロイしていました。developブランチにマージした後、画面で実際に動作確認をしていたのですが、念の為私以外がアクセスできないようにしておきたいなと思ったのがきっかけです。
Next.jsのMiddlewareを用いてBasic認証を使えば解決できそうだったので、簡単にまとめてみました。

前提

  • Next.js: v15.5.4
  • Vercel(Hobbyプラン)
    • 今回はDevelopment環境(developブランチにマージした時)のみにBasic認証が走るようにしています

環境変数

  • Development環境だけなので.env.developmentファイルは以下のように設定
  • .env.local.env.productionは設定しなくてもOK
.env.development
NEXT_PUBLIC_ENV=develop
BASIC_USERNAME=任意の値
BASIC_PASSWORD=任意の値

ミドルウェア

  1. NEXT_PUBLIC_ENV が "develop" のときだけ実行
  2. リクエストに Authorization ヘッダーがあるか確認
  3. なければ 401 → 「認証してください」とブラウザに促す
  4. あれば Base64 をデコードして username と password を取り出す
  5. .env に設定した値と一致しなければ再び 401
  6. 一致すれば認証成功 → 通常の処理へ進む(NextResponse.next() など)
middleware.ts
import { NextResponse, type NextRequest } from "next/server";

export async function middleware(request: NextRequest) {
  // ========== develop環境だけBasic認証 ==========
  if (process.env.NEXT_PUBLIC_ENV === "develop") { // ①
    const basicAuth = request.headers.get("authorization");  // ②
    const expectedUsername = process.env.BASIC_USERNAME;
    const expectedPassword = process.env.BASIC_PASSWORD;

    if (!basicAuth) {
      return new NextResponse("Auth required", {  // ③
        status: 401,
        headers: { "WWW-Authenticate": 'Basic realm="Secure Area"' },
      });
    }

    const [user, pwd] = atob(basicAuth.split(" ")[1] || "").split(":");  // ④
    if (user !== expectedUsername || pwd !== expectedPassword) {  // ⑤
      return new NextResponse("Invalid credentials", {
        status: 401,
        headers: { "WWW-Authenticate": 'Basic realm="Secure Area"' },
      });
    }
  }

  // ⑥
  // ※ matcherが全体に適用されているため、ミドルウェアを実行させたいパス
  // 以下の例は、ログインしていないとアクセスできないパスを仮定
  const path = request.nextUrl.pathname;
  const needsAuth =
    path.startsWith("/dashboard") ||
    path.startsWith("/settings");

  if (needsAuth) {
    // ここで認証チェックの処理
  }

  // それ以外はそのまま通す
  return NextResponse.next();
}

export const config = {
  matcher: [
    "/((?!_next/static|_next/image|favicon.ico).*)", // 全体に適用
  ],
};

Vercelでの設定

  • Project SettingEnvironment Variablesを開く

  • EnvironmentsDevelopmentのみにする

  • 画像のように入力

  • Valueの項目はご自身で設定してください

  • Saveボタン押下で保存


以上のミドルウェア・設定の上でDevelopment環境にアクセスすると、以下のようなポップアップが出てきます。
ユーザー名にVercelで設定したBASIC_USERNAMEの値を、
パスワードにVercelで設定したBASIC_PASSWORDの値を入力するとアクセスできます。

分かりづらいところもあったと思いますが、参考になれば幸いです。

Discussion