本文へスキップ
メニュー
テーマ

Next.jsでAuth.js認証を実装する

目次

はじめに

Auth.js(NextAuth.js v4)を使って、Next.js(App Router)にGitHubとGoogleのソーシャルログインを実装してみます。

補足

npm install next-authで入るのはv4(NextAuth.js)です。Auth.jsという名前になったv5は、2026年10月時点でもベータ版として配布されています。v5では、環境変数の接頭辞がNEXTAUTH_からAUTH_に変わるなど、設定の書き方が変わっています。この記事のコードは、Next.js 16.3.8とnext-auth 4.24.15でビルドが通ることを確認しました。

下準備

必要なパッケージをインストールする

Next.jsをインストールします。

ターミナルbash · 1行
npx create-next-app@latest next-auth-demo

質問には以下のように回答します。

ターミナルbash · 8行
✔ 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)? … No

作成したプロジェクトのフォルダに移動して、Auth.jsとreact-iconsをインストールします。

react-iconsはログインボタンにソーシャルアイコンを設定するためのものなので、任意で大丈夫です。

ターミナルbash · 2行
cd next-auth-demonpm install next-auth react-icons

shadcn/uiを初期化します。

ターミナルbash · 1行
npx shadcn@latest init

簡易的なページ作成のためにshadcn/uiのコンポーネントを追加します。

ターミナルbash · 1行
npx shadcn@latest add button card avatar

.env.localを追加します。

ターミナルbash · 1行
touch .env.local

.env.localには以下のように記載しておきます。

実際にサイトを公開するときは、NEXTAUTH_URLにサイトのURLを設定してください。

.env.local.env · 2行
NEXTAUTH_URL=http://localhost:3000NEXTAUTH_SECRET=

NEXTAUTH_SECRETに設定するシークレットキーは、以下のコマンドを実行して生成した値を設定します。

NEXTAUTH_SECRETを途中で変更すると、発行済みのJWTを復号できずエラーになるので、変えないようにしてください。

ターミナルbash · 1行
openssl rand -base64 32

ページを作成する

Auth.jsの設定と、認証用のAPIのルートを作成します。プロバイダにはGitHubとGoogleを設定します。

src/app/api/auth/[...nextauth]/route.tsTypeScript · 20行
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 };

ログインページを作成します。ログイン後に戻るURLをcallbackUrlで受け取ります。

src/app/login/page.tsxTSX · 12行
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>  );}

マイページを作成します。ログインしていない場合は、ログインページにリダイレクトします。

src/app/mypage/page.tsxTSX · 38行
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>  );}

レイアウトのヘッダーに、ログインの状態に応じたリンクを表示します。

src/app/layout.tsxTSX · 48行
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>  );}

トップページを作成します。

src/app/page.tsxTSX · 23行
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>  );}

ログインボタンとログアウトボタンは、クライアントコンポーネントとして作成します。

src/components/LoginButtons.tsxTSX · 26行
"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>  );}
src/components/LogoutButton.tsxTSX · 11行
"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

  1. GitHubのSettingsを開きます。

    GitHubのSettings⁠(新しいタブで開く)

  2. メニューの一番下にあるDeveloper settingsを開きます。
  3. メニューのOAuth Appsを開きます。
  4. New OAuth Appを選択します。
  5. 下の表を参考に各項目を設定してください。
  6. Register applicationを選択します。
  7. Generate a new client secretをクリックし、シークレットキーを発行します。

設定する項目は以下のとおりです。ローカルで作成する際の例なので、公開するサイトの場合は実際のドメインに変更してください。

Application name

任意のアプリ名

Homepage URL

http://localhost:3000

Authorization callback URL

http://localhost:3000/api/auth/callback/github

Client IDとClient secretsが表示されるので、コピーして.env.localに設定してください。

.env.local.env · 2行
GITHUB_ID=Ov23xxxxxxxxxxxxxxxxGITHUB_SECRET=xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx

Google

  1. Google Cloudにアクセスして、新しいプロジェクトを作成します。

    Google Cloud コンソール(新しいプロジェクト)⁠(新しいタブで開く)

  2. ダッシュボードの「APIとサービス > 認証情報」を開きます。
  3. 「認証情報を作成 > OAuth クライアント ID」を選択します。新しいプロジェクトでは、先にOAuth同意画面の設定を求められるので、画面の案内に沿ってアプリ名などを設定します。
  4. 「アプリケーションの種類」を「ウェブ アプリケーション」にし、「名前」に任意の名前を設定します。
  5. 「承認済みの JavaScript 生成元」にはパスなしのURL、「承認済みのリダイレクト URI」にはAPIのURIを設定します(下の表)。
  6. 「作成」を選択します。

設定する項目は以下のとおりです。ローカルで作成する際の例なので、公開するサイトの場合は実際のドメインに変更してください。

承認済みの JavaScript 生成元

http://localhost:3000

承認済みのリダイレクト URI

http://localhost:3000/api/auth/callback/google

クライアント IDとクライアント シークレットが表示されるので、コピーして.env.localに設定してください。

.env.local.env · 2行
GOOGLE_ID=123456789012-xxxxxxxxxxxxxxxxxxxxxxxx.apps.googleusercontent.comGOOGLE_SECRET=GOCSPX-xxxxxxxxxxxxxxxxxxxxxxxx
注意

Client secretやクライアント シークレット、NEXTAUTH_SECRETは、Gitのリポジトリにコミットしたり、公開の場所に書いたりしないでください。漏れた場合は、各サービスの画面で作り直します。

参考・引用

この記事は役に立ちましたか?