Search code examples
databasenext.jsadapterprismanext-auth

NextAuth Credential Provider with Prisma Adapter in Next12 does nothing


I've setup my Nextjs (Next12) with NextAuth CredentialsProvider and use Prisma Adapter to persist user's session in the database.

I followed this documentation here from NextAuth team themselves. But nothing happen after I clicked on login button.

To Note

Before that:-

  • I've make sure to try get the data first from the database & it works just fine.
  • I did also did try to just use the normal session: { jwt: true, maxAge: 30 * 24 * 60 * 60 } instead of straight away use Adapter. Also works fine.

Question

Now, I just want to know whether it's possible or not to use CredentialsProvider with Adapter at all?

NextAuth API

Below are 2 examples or working one and not working one: /pages/api/auth/[...nextauth].js

  • working: does not use adapter
import NextAuth from 'next-auth';
import CredentialsProvider from 'next-auth/providers/credentials';

export default async function auth(req, res) {
  return await NextAuth(req, res, {
    secret: process.env.SECRET,
    adapter: PrismaAdapter(prisma),
    session: {
      jwt: true,
      maxAge: 30 * 24 * 60 * 60, // 30 days
    }
    providers: [
      CredentialsProvider({
        async authorize(credentials) {
          const user = await prisma.user.findFirst({
            where: {
                email: credentials.email,
                password: credentials.password
            }
          });

          if (user !== null)
          {
              return user;
          }
          else {
            throw new Error('User does not exists. Please make sure you insert the correct email & password.')
          }
        }
      })
    ],
    callbacks: {
      redirect: async ({ url, baseUrl }) => {
        return baseUrl
      },
      jwt: async ({ token, user, account, profile, isNewUser }) => {
        if (typeof user !== typeof undefined) token.user = user;
  
        return token
      },
      session: async ({ session, user, token }) => {
        token?.user && (session.user = token.user)
  
        return session
      }
    }
  })
}
  • not working: using prisma adapter
import { PrismaAdapter } from "@next-auth/prisma-adapter";
import { PrismaClient } from '@prisma/client';
import NextAuth from 'next-auth';
import CredentialsProvider from 'next-auth/providers/credentials';
const prisma = new PrismaClient()

export default async function auth(req, res) {
  return await NextAuth(req, res, {
    secret: process.env.SECRET,
    adapter: PrismaAdapter(prisma),
    providers: [
      CredentialsProvider({
        async authorize(credentials) {
          const user = await prisma.user.findFirst({
            where: {
                email: credentials.email,
                password: credentials.password
            }
          });

          if (user !== null)
          {
              return user;
          }
          else {
            throw new Error('User does not exists. Please make sure you insert the correct email & password.')
          }
        }
      })
    ],
    callbacks: {
      redirect: async ({ url, baseUrl }) => {
        return baseUrl
      },
      jwt: async ({ token, user, account, profile, isNewUser }) => {
        if (typeof user !== typeof undefined) token.user = user;
  
        return token
      },
      session: async ({ session, user, token }) => {
        token?.user && (session.user = token.user)
  
        return session
      }
    }
  })
}

Prisma Schema

This is the current schema.prisma (this comes from the NextAuth doc itself):-

  • I already did the npx prisma migrate dev & npx prisma generate
// This is your Prisma schema file,
// learn more about it in the docs: https://pris.ly/d/prisma-schema

generator client {
  provider        = "prisma-client-js"
  previewFeatures = ["referentialIntegrity"]
}

datasource db {
  provider             = "mysql"
  url                  = env("DATABASE_URL")
  // shadowDatabaseUrl    = env("SHADOW_URL")
  referentialIntegrity = "prisma"
}

model Account {
  id                 String  @id @default(cuid())
  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?
  oauth_token_secret String?
  oauth_token        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
  password      String?
  emailVerified DateTime?
  image         String?
  accounts      Account[]
  sessions      Session[]
}

model VerificationToken {
  identifier String
  token      String   @unique
  expires    DateTime

  @@unique([identifier, token])
}

Solution

  • I just found out the CredentialsProvider from next-auth will not work with adapter at all according to this doc. You may find the reason why it can't or not recommended to use with CredentialsProvider.

    This is an additional link where you can find a discussion regarding this matter.