Script Valley
Next.js: Full-Stack React Applications
Authentication with NextAuth.jsLesson 5.3

How to implement credentials authentication with NextAuth.js

Credentials provider, authorize callback, bcrypt password hashing, database user lookup, JWT strategy, credential validation

Credentials Provider

Use the Credentials provider for email/password authentication. It's more complex than OAuth but gives you full control.

npm install bcryptjs
npm install -D @types/bcryptjs
// auth.ts
import Credentials from 'next-auth/providers/credentials'
import bcrypt from 'bcryptjs'
import { prisma } from '@/lib/prisma'

export const { auth, signIn, signOut, handlers } = NextAuth({
  providers: [
    Credentials({
      async authorize(credentials) {
        const { email, password } = credentials as {
          email: string
          password: string
        }

        const user = await prisma.user.findUnique({ where: { email } })
        if (!user || !user.password) return null

        const passwordsMatch = await bcrypt.compare(password, user.password)
        if (!passwordsMatch) return null

        return user  // Must return user object or null
      },
    }),
  ],
  session: { strategy: 'jwt' },
})

Hashing Passwords on Registration

'use server'
import bcrypt from 'bcryptjs'

export async function registerUser(formData: FormData) {
  const password = formData.get('password') as string
  const hashed = await bcrypt.hash(password, 12)  // 12 salt rounds
  await prisma.user.create({
    data: { email: formData.get('email') as string, password: hashed },
  })
}

Never store plain-text passwords. Return null from authorize to reject login — this causes Auth.js to show an error without revealing whether the email or password was wrong.

Up next

How to access session data in Next.js Server and Client Components

Sign in to track progress