Claude Skills Guide

Claude Code NextAuth Database Adapter Setup Guide

NextAuth.js (now Auth.js) provides a flexible authentication system for Next.js applications, and one of its most powerful features is the database adapter system. This guide walks you through setting up NextAuth with various database adapters using Claude Code, demonstrating how Claude Code can accelerate your authentication infrastructure setup.

Understanding NextAuth Database Adapters

Database adapters in NextAuth allow you to persist user sessions, accounts, and verification tokens in your own database instead of relying solely on JWT-based authentication. This is essential for applications requiring:

Supported Database Adapters

NextAuth supports multiple database backends through its adapter ecosystem:

Setting Up NextAuth with Prisma Adapter

Prisma is the most commonly used adapter. Here’s how Claude Code can help you set it up efficiently.

Step 1: Install Dependencies

npm install @next-auth/prisma-adapter prisma @prisma/client
npm install next-auth

Step 2: Configure Prisma Schema

Ask Claude Code to generate your Prisma schema with NextAuth models:

// prisma/schema.prisma
generator client {
  provider = "prisma-client-js"
}

datasource db {
  provider = "postgresql"
  url      = env("DATABASE_URL")
}

model Account {
  id                String  @id @default(cuid())
  userId            String
  type              String
  provider          String
  providerAccountId String
  refresh_token     String? @db.Text
  access_token      String? @db.Text
  expires_at        Int?
  token_type        String?
  scope             String?
  id_token          String? @db.Text
  session_state     String?

  user User @relation(fields: [userId], references: [id], onDelete: Cascade)

  @@unique([provider, providerAccountId])
}

model Session {
  id           String   @id @default(cuid())
  sessionToken String   @unique
  userId       String
  expires      DateTime
  user         User     @relation(fields: [userId], references: [id], onDelete: Cascade)
}

model User {
  id            String    @id @default(cuid())
  name          String?
  email         String?   @unique
  emailVerified DateTime?
  image         String?
  accounts      Account[]
  sessions      Session[]
}

model VerificationToken {
  identifier String
  token      String   @unique
  expires    DateTime

  @@unique([identifier, token])
}

Step 3: Create the NextAuth Configuration

Here’s a practical NextAuth configuration with Prisma adapter:

// auth.ts
import NextAuth from "next-auth"
import { PrismaAdapter } from "@next-auth/prisma-adapter"
import { PrismaClient } from "@prisma/client"
import GoogleProvider from "next-auth/providers/google"
import GitHubProvider from "next-auth/providers/github"

const prisma = new PrismaClient()

export const authOptions = {
  adapter: PrismaAdapter(prisma),
  providers: [
    GoogleProvider({
      clientId: process.env.GOOGLE_CLIENT_ID,
      clientSecret: process.env.GOOGLE_CLIENT_SECRET,
    }),
    GitHubProvider({
      clientId: process.env.GITHUB_ID,
      clientSecret: process.env.GITHUB_SECRET,
    }),
  ],
  callbacks: {
    async session({ session, user }) {
      // Add user ID to session
      session.user.id = user.id
      return session
    },
  },
  pages: {
    signIn: "/auth/signin",
    error: "/auth/error",
  },
}

Using Drizzle ORM Adapter

Drizzle offers a lightweight alternative with better performance. Here’s how to set it up with Claude Code’s assistance.

Drizzle Schema Definition

// db/schema.ts
import { pgTable, text, timestamp, uuid, boolean } from 'drizzle-orm/pg-core';

export const users = pgTable('users', {
  id: uuid('id').defaultRandom().primaryKey(),
  name: text('name'),
  email: text('email').notNull().unique(),
  emailVerified: timestamp('email_verified'),
  image: text('image'),
  createdAt: timestamp('created_at').defaultNow(),
  updatedAt: timestamp('updated_at').defaultNow(),
});

export const accounts = pgTable('accounts', {
  id: uuid('id').defaultRandom().primaryKey(),
  userId: uuid('user_id').notNull().references(() => users.id, { onDelete: 'cascade' }),
  type: text('type').notNull(),
  provider: text('provider').notNull(),
  providerAccountId: text('provider_account_id').notNull(),
  refresh_token: text('refresh_token'),
  access_token: text('access_token'),
  expires_at: integer('expires_at'),
  token_type: text('token_type'),
  scope: text('scope'),
  id_token: text('id_token'),
  session_state: text('session_state'),
});

export const sessions = pgTable('sessions', {
  id: uuid('id').defaultRandom().primaryKey(),
  sessionToken: text('session_token').notNull().unique(),
  userId: uuid('user_id').notNull().references(() => users.id, { onDelete: 'cascade' }),
  expires: timestamp('expires').notNull(),
});

export const verificationTokens = pgTable('verification_tokens', {
  identifier: text('identifier').notNull(),
  token: text('token').notNull().unique(),
  expires: timestamp('expires').notNull(),
});

Drizzle Adapter Implementation

// auth.ts
import { DrizzleAdapter } from "@auth/drizzle-adapter"
import { db } from "./db"
import NextAuth from "next-auth"
import Google from "next-auth/providers/google"

export const { handlers, auth, signIn, signOut } = NextAuth({
  adapter: DrizzleAdapter(db),
  providers: [Google],
  callbacks: {
    session({ session, user }) {
      session.user.id = user.id
      return session
    },
  },
})

Practical Examples with Claude Code

Claude Code can significantly speed up your NextAuth adapter setup. Here are practical scenarios:

Example 1: Generating Database Migration Scripts

Ask Claude Code to generate the migration for your adapter:

Create a Prisma migration for my NextAuth setup with PostgreSQL. 
Include the Account, Session, User, and VerificationToken models.

Claude Code will generate the appropriate migration commands and SQL statements.

Example 2: Customizing Session Handling

For applications requiring session revocation or database-backed sessions:

// Custom session callback with database check
callbacks: {
  async session({ session, token, user }) {
    if (session.user) {
      // Check if account is still active
      const account = await prisma.account.findFirst({
        where: { userId: user.id }
      });
      
      if (!account) {
        // Handle inactive account
        return null;
      }
      
      session.user.id = user.id;
      session.user.role = user.role; // Custom field
    }
    return session;
  }
}

Example 3: Adding Custom User Fields

Extend the user model with application-specific fields:

// Extended User model
model User {
  id            String    @id @default(cuid())
  name          String?
  email         String?   @unique
  emailVerified DateTime?
  image         String?
  role          String    @default("USER")  // Custom field
  organizationId String?                    // Custom field
  accounts      Account[]
  sessions      Session[]
}

Best Practices for Database Adapter Setup

When implementing NextAuth with database adapters, consider these Claude Code tips:

  1. Always use connection pooling - Configure Prisma with connection pooling for production
  2. Handle adapter errors gracefully - Add error handling for database connection failures
  3. Index your queries - Ensure proper database indexes on userId, provider fields
  4. Use environment variables - Never hardcode database credentials
  5. Test migrations - Always test database migrations in staging before production

Troubleshooting Common Issues

Claude Code can help diagnose common adapter problems:

Conclusion

Setting up NextAuth with database adapters doesn’t have to be complex. Claude Code can help you generate schemas, configuration files, and migration scripts quickly. Whether you choose Prisma, Drizzle, or another adapter, the key is understanding how your data model aligns with NextAuth’s requirements.

Start with the adapter that matches your existing stack, and use Claude Code’s code generation capabilities to accelerate your authentication setup. Remember to always handle sensitive user data according to privacy regulations and security best practices.

Built by theluckystrike — More at zovo.one