📑

Next.js+NextAuthで認証情報をDBで管理する

2025/02/23に公開

https://zenn.dev/kaikusakari/articles/4c1590d463f9d1
前回、上記でGoogleのソーシャルログインする方法を試しました。現状はCookieで認証情報を保持しているだけで、サーバサイドでも認証情報を保持管理したいので、DBで管理できるようにします。

NextAuthではオプションでDBで管理する機能も備わっています。Adapterという機能になります。
https://authjs.dev/reference/core/adapters

対象バージョン

Next.js 15.1.7
NextAuth 5.0.0-beta.25
Prisma Client 6.4.1
PostgreSQL 16.4(AzureのDBaaS)

今回は prisma というORMを利用します。公式のマニュアルに沿って対応します。
https://authjs.dev/getting-started/adapters/prisma?framework=next-js

インストール

必要なライブラリをインストールします

pnpm add @prisma/client @auth/prisma-adapter
pnpm add prisma --save-dev

初期設定

上記のコマンド実施後にPJのルートに prisma というフォルダと schema.prisma というファイルができます。

npx prisma init --datasource-provider postgresql

DBの接続情報を更新することと、認証に必要なテーブルの定義をNextAuthのマニュアルからコピペします。

schema.prisma
model user {
  id            String          @id @default(cuid())
  name          String?
  email         String          @unique
  emailVerified DateTime?
  image         String?
  accounts      account[]
  sessions      session[]
  authenticator Authenticator[]
  createdAt DateTime @default(now())
  updatedAt DateTime @updatedAt
}
 
model account {
  userId            String
  type              String
  provider          String
  providerAccountId String
  refresh_token     String?
  access_token      String?
  expires_at        Int?
  token_type        String?
  scope             String?
  id_token          String?
  session_state     String?
  createdAt DateTime @default(now())
  updatedAt DateTime @updatedAt
  user user @relation(fields: [userId], references: [id], onDelete: Cascade)
  @@id([provider, providerAccountId])
}
 
model session {
  sessionToken String   @unique
  userId       String
  expires      DateTime
  user         user     @relation(fields: [userId], references: [id], onDelete: Cascade)
  createdAt DateTime @default(now())
  updatedAt DateTime @updatedAt
}
 
model verificationToken {
  identifier String
  token      String
  expires    DateTime
  @@id([identifier, token])
}
 
model authenticator {
  credentialID         String  @unique
  userId               String
  providerAccountId    String
  credentialPublicKey  String
  counter              Int
  credentialDeviceType String
  credentialBackedUp   Boolean
  transports           String?
  user user @relation(fields: [userId], references: [id], onDelete: Cascade)
  @@id([userId, credentialID])
}

DBのマイグレーション

DBに対して定義情報を元にテーブルが作成される。ORマップするプログラムの定義ファイルも作成する。

pnpm exec prisma migrate dev
pnpm exec prisma generate

認証の設定ファイル修正

ルートに prisma.ts というファイルを作成してライブラリを読み込むのとauth.tsを更新する。

prisma.ts
import { PrismaClient } from "@prisma/client"
const globalForPrisma = globalThis as unknown as { prisma: PrismaClient }
export const prisma = globalForPrisma.prisma || new PrismaClient()
if (process.env.NODE_ENV !== "production") globalForPrisma.prisma = prisma

認証の設定ファイルも修正する

auth.ts
import NextAuth from "next-auth"
import { PrismaAdapter } from "@auth/prisma-adapter"
import { prisma } from "@/prisma"
import Google from "next-auth/providers/google"

export const { handlers, auth, signIn, signOut } = NextAuth({
  adapter: PrismaAdapter(prisma),
  providers: [Google],
})

実際に動かす

pnpm run dev

http://localhost:3000 にアクセスしてログイン試行すると

想定通りログインできました。

DBを見てみるとユーザーなどテーブルにレコードができてます。長いのでいくつかのカラムをピックアップしてます。

itsumo=> select * from public.user;
id|     name     |         email          |
XX| kai kusakari | kai.kusakari@gmail.com |

itsumo=> select * from public.session;
sessionToken. | userId |  
<sessionToken>| XX     |

画面上からログアウトするとsessionテーブルからレコードが消えました。

userテーブルにはGoogleからOAuthで受け取ったuseridが入っています。自身のWEBアプリでは独自のIDを割り振って、受け取ったuseridとマップするような仕組みを実装していけたらと思います。
(Google以外の認証手段を増やした時にuseridが重複する可能性など制限があるためです)

今回で本人確認など認証部分を作成できたため、次回は認証情報を使って、登録機能や、自身が登録した内容の一覧機能を実装して試してみます。

Discussion