Published on

Auth.js: Setting Up in Next.js

Authors
  • avatar
    Name
    Shelton Ma
    Twitter

1. Auth.js Setup

1. Installing Auth.js

pnpm add next-auth@beta

2. Generate a Secret Key

npx auth secret

3. Configure

  1. Create NextAuth

    // src/auth.ts
    import NextAuth from "next-auth"
    
    export const { handlers, signIn, signOut, auth } = NextAuth({
      providers: [],
    })
    
  2. Add a Route Handler

    // src/app/api/auth/[...nextauth]/route.ts
    import { handlers } from "@/auth" // Referring to the auth.ts we just created
    
    export const { GET, POST } = handlers
    
  3. Add Middleware

    // src/middleware.ts
    export { auth as middleware } from "@/auth"
    

2. Database Adapters (connect Auth.js to your database)

Database Adapters

  1. Install drizzle-adapter

    pnpm add drizzle-orm @auth/drizzle-adapter
    pnpm add drizzle-kit --save-dev
    
  2. Schemas

    // src/db/schema.ts
    import {
    
      boolean,
      timestamp,
      pgTable,
      text,
      primaryKey,
      integer,
    } from "drizzle-orm/pg-core"
    import postgres from "postgres"
    import { drizzle } from "drizzle-orm/postgres-js"
    import type { AdapterAccountType } from "next-auth/adapters"
    
    const connectionString = "postgres://postgres:postgres@localhost:5432/drizzle"
    const pool = postgres(connectionString, { max: 1 })
    
    export const db = drizzle(pool)
    
    export const users = pgTable("user", {
      id: text("id")
        .primaryKey()
        .$defaultFn(() => crypto.randomUUID()),
      name: text("name"),
      email: text("email").unique(),
      emailVerified: timestamp("emailVerified", { mode: "date" }),
      image: text("image"),
    })
    
    export const accounts = pgTable(
      "account",
      {
        userId: text("userId")
          .notNull()
          .references(() => users.id, { onDelete: "cascade" }),
        type: text("type").$type<AdapterAccountType>().notNull(),
        provider: text("provider").notNull(),
        providerAccountId: text("providerAccountId").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"),
      },
      (account) => [
        {
          compoundKey: primaryKey({
            columns: [account.provider, account.providerAccountId],
          }),
        },
      ]
    )
    
    export const sessions = pgTable("session", {
      sessionToken: text("sessionToken").primaryKey(),
      userId: text("userId")
        .notNull()
        .references(() => users.id, { onDelete: "cascade" }),
      expires: timestamp("expires", { mode: "date" }).notNull(),
    })
    
    export const verificationTokens = pgTable(
      "verificationToken",
      {
        identifier: text("identifier").notNull(),
        token: text("token").notNull(),
        expires: timestamp("expires", { mode: "date" }).notNull(),
      },
      (verificationToken) => [
        {
          compositePk: primaryKey({
            columns: [verificationToken.identifier, verificationToken.token],
          }),
        },
      ]
    )
    
    export const authenticators = pgTable(
      "authenticator",
      {
        credentialID: text("credentialID").notNull().unique(),
        userId: text("userId")
          .notNull()
          .references(() => users.id, { onDelete: "cascade" }),
        providerAccountId: text("providerAccountId").notNull(),
        credentialPublicKey: text("credentialPublicKey").notNull(),
        counter: integer("counter").notNull(),
        credentialDeviceType: text("credentialDeviceType").notNull(),
        credentialBackedUp: boolean("credentialBackedUp").notNull(),
        transports: text("transports"),
      },
      (authenticator) => [
        {
          compositePK: primaryKey({
            columns: [authenticator.userId, authenticator.credentialID],
          }),
        },
      ]
    )
    
  3. Add DrizzleAdapter

    // src/auth.ts
    import NextAuth from "next-auth"
    import { DrizzleAdapter } from "@auth/drizzle-adapter"
    import { db } from "./db/drizzle";
    
    export const { handlers, auth, signIn, signOut } = NextAuth({
      adapter: DrizzleAdapter(db),
      providers: [],
    })