🔑

Next.jsのApp RouterでBasic 認証を実装する

2023/06/29に公開

開発時はだいたいBasic認証機能をつけることが多いのですが、
PagesRouterAppRouterでAPIの作り方が異なるので備忘録として残します。

.env
BASIC_AUTH_USER="user"
BASIC_AUTH_PASSWORD="password"

middleware.ts

middleware.tsは、PagesRouter・AppRouterで共通のものを利用できます。

/middleware.ts
import { NextRequest, NextResponse } from 'next/server';

export const config = {
  matcher: ['/:path*'],
};

export function middleware(req: NextRequest) {
  // 開発時では認証をスキップ
  if (process.env.NODE_ENV === 'development') {
    return NextResponse.next();
  }

  // 環境変数が設定されていない場合は認証をスキップ
  if (!process.env.BASIC_AUTH_PASSWORD) {
    return NextResponse.next();
  }

  const basicAuth = req.headers.get('authorization');
  const url = req.nextUrl;

  if (basicAuth) {
    const authValue = basicAuth.split(' ')[1] ?? '';
    const [user, pwd] = atob(authValue).split(':');

    if (
      user === process.env.BASIC_AUTH_USER &&
      pwd === process.env.BASIC_AUTH_PASSWORD
    ) {
      return NextResponse.next();
    }
  }
  url.pathname = '/api/basic-auth';

  return NextResponse.rewrite(url);
}

AppRouterの場合

/app/api/basic-auth/route.tsを作成して下記を入力します。

/app/api/basic-auth/route.ts
import { NextResponse } from 'next/server';

export async function GET() {
  return NextResponse.json(
    { error: 'Basic Auth Required' },
    {
      status: 401,
      headers: { 'WWW-Authenticate': "Basic realm='secure_area'" },
    },
  );
}

PagesRouterの場合

/pages/api/basic-auth.tsを作成して下記を入力します。

/pages/api/basic-auth.ts
import type { NextApiRequest, NextApiResponse } from 'next';

export default function basicAuth(_: NextApiRequest, res: NextApiResponse) {
  res.statusCode = 401;
  res.setHeader('WWW-authenticate', "Basic realm='secure_area'");
  res.end('Basic Auth Required');
}

Discussion