Next.jsでAuth.js認証を実装する
投稿日:
更新日:
はじめに
Auth.js v4を使ってNext.jsでログイン機能を実装してみます。
下準備
必要なパッケージをインストールする
Next.jsをインストールします。
ターミナル
npx create-next-app@latest next-auth-demo
✔ Would you like to use the recommended Next.js defaults? › No, customize settings
✔ Would you like to use TypeScript? … Yes
✔ Which linter would you like to use? › ESLint
✔ Would you like to use React Compiler? … Yes
✔ Would you like to use Tailwind CSS? … Yes
✔ Would you like your code inside a `src/` directory? … Yes
✔ Would you like to use App Router? (recommended) … Yes
✔ Would you like to customize the import alias (`@/*` by default)? … NoAuth.jsとreact-iconsをインストールします。
react-iconsはログインボタンにソーシャルアイコンを設定するためのものなので、任意で大丈夫です。
ターミナル
npm install next-auth react-iconsshadcn/uiを初期化します。
ターミナル
npx shadcn@latest init簡易的なページ作成のためにshadcn/uiのコンポーネントを追加します。
ターミナル
npx shadcn@latest add button card avatar.env.localを追加します。
ターミナル
touch .env.local.env.localには以下のように記載しておきます。
実際にサイトを公開するときは、NEXTAUTH_URLにサイトのURLを設定してください。
.env.local
NEXTAUTH_URL=http://localhost:3000
NEXTAUTH_SECRET=NEXTAUTH_SECRETに設定するシークレットキーは、以下のコマンドを実行して生成した値を設定します。
NEXTAUTH_SECRETを途中で変更するとJWT複合エラーになるので、変えないこと。
ターミナル
openssl rand -base64 32ページを作成する
import NextAuth from "next-auth";
import GitHub from "next-auth/providers/github";
import Google from "next-auth/providers/google";
export const authOptions = {
providers: [
GitHub({
clientId: process.env.GITHUB_ID!,
clientSecret: process.env.GITHUB_SECRET!,
}),
Google({
clientId: process.env.GOOGLE_ID!,
clientSecret: process.env.GOOGLE_SECRET!,
}),
],
};
const handler = NextAuth(authOptions);
export { handler as GET, handler as POST };
import LoginButtons from "@/components/LoginButtons";
export default async function LoginPage({ searchParams }: { searchParams: Promise<{ callbackUrl?: string }> }) {
const { callbackUrl } = await searchParams;
return (
<div className="max-w-sm space-y-4">
<h1 className="text-xl font-bold">ログイン</h1>
<LoginButtons callbackUrl={callbackUrl ?? "/"} />
</div>
);
}
import { authOptions } from "@/app/api/auth/[...nextauth]/route";
import { Avatar, AvatarFallback, AvatarImage } from "@/components/ui/avatar";
import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card";
import { getServerSession } from "next-auth";
import { redirect } from "next/navigation";
export default async function MyPage() {
const session = await getServerSession(authOptions);
if (!session) {
redirect("/login?callbackUrl=%2Fmypage");
}
const user = session.user;
return (
<div className="space-y-4">
<h1 className="text-xl font-bold">マイページ</h1>
<Card>
<CardHeader>
<CardTitle>アカウント情報</CardTitle>
</CardHeader>
<CardContent className="flex items-center gap-4">
<Avatar>
<AvatarImage src={user?.image ?? ""} alt={user?.name ?? ""} />
<AvatarFallback>{(user?.name ?? user?.email ?? "U").slice(0, 1).toUpperCase()}</AvatarFallback>
</Avatar>
<div className="space-y-1">
<p className="font-medium">{user?.name ?? "(名前なし)"}</p>
<p className="text-sm text-muted-foreground">{user?.email ?? "(メールなし)"}</p>
</div>
</CardContent>
</Card>
</div>
);
}
import { authOptions } from "@/app/api/auth/[...nextauth]/route";
import LogoutButton from "@/components/LogoutButton";
import { getServerSession } from "next-auth";
import Link from "next/link";
import "./globals.css";
export default async function RootLayout({ children }: { children: React.ReactNode }) {
const session = await getServerSession(authOptions);
return (
<html lang="ja">
<body className="min-h-dvh">
<header className="border-b">
<div className="mx-auto flex max-w-4xl items-center justify-between gap-4 p-4">
<Link href="/" className="font-bold">
Auth Test
</Link>
<nav className="flex items-center gap-3 text-sm">
<Link href="/" className="underline">
Top
</Link>
{session ? (
<>
<Link href="/mypage" className="underline">
MyPage
</Link>
<LogoutButton />
</>
) : (
<>
<Link href="/login" className="underline">
Login
</Link>
<Link href="/mypage" className="underline">
MyPage
</Link>
</>
)}
</nav>
</div>
</header>
<main className="mx-auto max-w-4xl p-6">{children}</main>
</body>
</html>
);
}
import { authOptions } from "@/app/api/auth/[...nextauth]/route";
import { getServerSession } from "next-auth";
import Link from "next/link";
export default async function Home() {
const session = await getServerSession(authOptions);
return (
<div className="space-y-4">
<h1 className="text-xl font-bold">Top</h1>
{session ? (
<Link href="/mypage" className="underline">
マイページへ
</Link>
) : (
<Link href="/login" className="underline">
ログインへ
</Link>
)}
</div>
);
}
"use client";
import { Button } from "@/components/ui/button";
import { signIn } from "next-auth/react";
import { FaGithub } from "react-icons/fa";
import { FcGoogle } from "react-icons/fc";
type Props = {
callbackUrl: string;
};
export default function LoginButtons({ callbackUrl }: Props) {
return (
<div className="space-y-2">
<Button variant={"outline"} className="w-full" onClick={() => signIn("github", { callbackUrl })}>
<FaGithub />
GitHubでログイン
</Button>
<Button variant={"outline"} className="w-full" onClick={() => signIn("google", { callbackUrl })}>
<FcGoogle />
Googleでログイン
</Button>
</div>
);
}
"use client";
import { signOut } from "next-auth/react";
export default function LogoutButton() {
return (
<button type="button" className="underline bg-transparent p-0 text-sm" onClick={() => signOut({ callbackUrl: "/" })}>
ログアウト
</button>
);
}
各プロバイダの設定
GitHub
- GitHubのSettingsを開きます。
- メニューの一番下にあるDeveloper settingsを開きます。
- メニューのOAuth Appsを開きます。
- New OAuth Appを選択します。
- 以下を参考に各項目を設定してください。
以下はローカルで作成する際の例ですが、公開するサイトの場合は実際のドメインに変更してください。Application name
任意のアプリ名
Homepage URL
http://localhost:3000
Authorization callback URL
http://localhost:3000/api/auth/callback/github
- Register applicationを選択します。
- Generate a new client secretをクリックし、シークレットキーを発行します。
Client IDとClient secretsが表示されるので、コピーして.env.localに設定してください。
.env.local
GITHUB_ID=Ov23liBzquFYuEDCT7Za
GITHUB_SECRET=d3615cbaa51cf317ad2810f98f09cc4e13b56e85- Google Cloudにアクセスして、新しいプロジェクトを作成します。
https://console.cloud.google.com/projectcreate - ダッシュボードの「APIとサービス > 認証情報」を開きます。
- 「認証情報を作成 > OAuth クライアント ID」を選択します。
- 「アプリケーションの種類」を「ウェブ アプリケーション」にし、「名前」に任意の名前を設定します。
- 「承認済みの JavaScript 生成元」にはパスなしのURL、「承認済みのリダイレクト URI」にはAPIのURIを設定します。
以下はローカルで作成する際の例ですが、公開するサイトの場合は実際のドメインに変更してください。承認済みの JavaScript 生成元
http://localhost:3000
承認済みのリダイレクト URI
http://localhost:3000/api/auth/callback/google
- 「作成」を選択します。
クライアント IDとクライアント シークレットが表示されるので、コピーして.env.localに設定してください。
.env.local
GOOGLE_ID=123456789012-xxxxxxxxxxxxxxxxxxxxxxxx.apps.googleusercontent.com
GOOGLE_SECRET=GOCSPX-xxxxxxxxxxxxxxxxxxxxxxxx
