【2026年版】Next.jsで始めるReact開発環境の構築方法 - 最速セットアップガイド
yuya_react
月収100万フリーランスへの道
こんにちは、優也@月収100万を目指して月100時間勉強する男です。
Next.jsで認証機能を実装したいけど、複雑で時間がかかりそう…そんな悩みを解決します! この記事では、NextAuth.jsを使って最速で認証機能を実装する方法を解説します。
まずは必要なパッケージをインストールします。
npm i next-auth@beta bcrypt zod
npm i -D @types/bcrypt.envファイルにAUTH_SECRETを追加します。\
AUTH_SECRET=your-secret-key-hereシークレットキーはこちらにアクセスすると自動生成できます。
プロジェクトルートにauth.config.tsを作成します。
import { NextAuthConfig } from "next-auth";
import Credentials from "next-auth/providers/credentials";
export const authConfig = {
pages: {
signIn: "/login",
},
callbacks: {
authorized({ auth, request: { nextUrl } }) {
const isLoggedIn = !!auth?.user;
const isOnAuthenticatedPage = nextUrl.pathname.startsWith("/dashboard");
if (isOnAuthenticatedPage) {
if (isLoggedIn) return true;
if (!isLoggedIn) {
// falseを返すと,Signinページにリダイレクトされる
return false;
}
} else if (isLoggedIn) {
return Response.redirect(new URL("/dashboard", nextUrl));
}
return true;
},
},
providers: [Credentials({})],
} satisfies NextAuthConfig;このファイルでは以下を設定しています:
/login)
/dashboard配下)へのアクセス制御(isOnAuthenticatedPage)
/loginにアクセスした場合、/dashboardへリダイレクト
重要①:srcフォルダを使っている場合は、srcフォルダ直下に配置してください。
重要②:next.js15以下の方はmiddleware.tsという名前にしてください。
import NextAuth from "next-auth";
import { authConfig } from "./auth.config";
export default NextAuth(authConfig).auth;
export const config = {
matcher: ["/((?!api|_next/static|_next/image|.*\\.png$).*)"],
};next.jsは、このproxyが全てのリクエストをインターセプトし、認証状態をチェックします。 matcherで静的ファイルやAPIルートは除外しています。
lib/auth.ts(またはsrc配下の場合はsrc/lib/auth.ts)を作成します。
import NextAuth from "next-auth";
import { authConfig } from "../auth.config";
import Credentials from "next-auth/providers/credentials";
import { z } from "zod";
import bcrypt from "bcrypt";
import postgres from "postgres";
const sql = postgres(process.env.POSTGRES_URL!, { ssl: "require" });
async function getUser(email: string): Promise<any> {
try {
const user = await sql`
SELECT * FROM users WHERE email = ${email}
`;
return user[0];
} catch (error) {
console.error("Failed to fetch user:", error);
throw new Error("Failed to fetch user.");
}
}
export const { auth, signIn, signOut } = NextAuth({
...authConfig,
providers: [
Credentials({
async authorize(credentials) {
const parsedCredentials = z
.object({ email: z.email(), password: z.string().min(6) })
.safeParse(credentials);
if (parsedCredentials.success) {
const { email, password } = parsedCredentials.data;
const user = await getUser(email);
if (!user) return null;
const passwordsMatch = await bcrypt.compare(password, user.password);
if (passwordsMatch) return user;
}
return null;
},
}),
],
});このファイルでは:
signIn、signOut、auth関数をエクスポートlib/action.tsを作成し、ログイン処理を実装します。
"use server";
import { signIn } from "./auth";
import { AuthError } from "next-auth";
export async function authenticate(
prevState: string | undefined,
formData: FormData,
) {
try {
const redirectTo = formData.get("redirectTo") as string;
await signIn("credentials", {
email: formData.get("email"),
password: formData.get("password"),
redirectTo: redirectTo || "/dashboard",
});
} catch (error) {
if (error instanceof AuthError) {
switch (error.type) {
case "CredentialsSignin":
return "メールアドレスまたはパスワードが正しくありません";
default:
return "予期しないエラーが発生しました";
}
}
throw error;
}
}app/login/login-form.tsxを作成します。
"use client";
import { useActionState } from "react";
import { useSearchParams } from "next/navigation";
import { authenticate } from "../lib/action";
const LoginForm = () => {
const searchParams = useSearchParams();
const callbackUrl = searchParams.get("callbackUrl") || "/dashboard";
const [errorMessage, formAction, isPending] = useActionState(
authenticate,
undefined,
);
return (
<form action={formAction}>
<h1 className="font-bold text-4xl">salon-reservations-system</h1>
<div className="w-80">
<div className="flex flex-col gap-2 mb-4">
<label htmlFor="email" className="mb-2">
email
</label>
<input
name="email"
type="text"
placeholder="email"
className="border-2 border-gray-300 rounded-md p-2"
/>
<label htmlFor="password" className="mb-2">
password
</label>
<input
name="password"
type="password"
placeholder="password"
className="border-2 border-gray-300 rounded-md p-2"
/>
<input type="hidden" name="redirectTo" value={callbackUrl} />
</div>
{errorMessage && (
<p className="text-sm text-red-500">{errorMessage}</p>
)}
</div>
<button
className="bg-blue-500 text-white px-6 py-2 rounded-md hover:bg-blue-600"
disabled={isPending}
>
{isPending ? "ログイン中..." : "Login"}
</button>
</form>
);
};
export default LoginForm;Vercelにデプロイする際は、環境変数の設定を忘れずに!
AUTH_SECRETを追加(ローカルと同じ値)これでNextAuth.jsを使った認証機能の実装が完了です!
ポイント:
この実装パターンを使えば、10分程度で本格的な認証機能が実装できます。 ぜひプロジェクトに組み込んでみてください!
