Search code examples
authenticationnext.jsnext-authsession-management

Auth.js v5 Database Session Strategy for Credential Provider Returning Null


I'm currently working on implementing authentication in my nextjs 14 project using Auth.js v5 ,However, I am encountering an issue where the session always returns null(Only for Credential provider) in page.tsx

My Setup:

  • Auth.js Version: v5

  • Provider: Credential Provider

  • Session Strategy: Database

  • Framework: Nextjs 14

  • Database: Vercel's Postgres

  • Adapter: Prisma

Auth.ts

import type { NextAuthConfig } from 'next-auth'
import NextAuth from 'next-auth'
import Google from 'next-auth/providers/google'
import Github from 'next-auth/providers/github'
import { PrismaAdapter } from '@auth/prisma-adapter'
import { db } from './lib/db'
import Credentials from 'next-auth/providers/credentials'
import { loginSchema } from './schema/zod-form'
import { getUserByEmail } from './data/user'
import bcrypt from 'bcryptjs'
import { Adapter } from 'next-auth/adapters'
import { generateSessionToken } from './Action/token'
const Credential = Credentials({
  credentials: {
    username: { label: 'name' },
    email: { label: 'email', type: 'email' },
    password: { label: 'password', type: 'password' },
  },
  async authorize(credentials) {
    const validate = loginSchema.safeParse(credentials)
    if (!validate.success) return null
    const { email, password } = validate.data
    const user = await getUserByEmail(email)
    if (!user || !user.password) {
      return null
    }
    const passwordmatch = await bcrypt.compare(password, user.password)
    if (passwordmatch) {
      await generateSessionToken(user.id)
      return user
    }
    return null
  },
})
const config = {
  providers: [Google, Github, Credential],
  adapter: PrismaAdapter(db) as Adapter,
  session: { strategy: 'database' },
  callbacks: {
    async session({ session, user }) {
      session.user.role = user.role
      console.log(user)
      return session
    },
  },
  trustHost: true,
} satisfies NextAuthConfig
export const { handlers, auth, signIn, signOut } = NextAuth(config)

I'm returning the user in the authorize function if it passes the conditions. Everything is working correctly, except I am not getting the sessions in the page.tsx file when invoking const session = await auth();.

Any insights or suggestions would be greatly appreciated!

Thank you!


Solution

  • We need to manually handle session creation, encryption and sign out events when using the database strategy.

    My Setup:

    1. Auth.js Version: v5

    2. Provider: Credential Provider

    3. Framework: Nextjs 14

    4. Adapter: Prisma

    5. Database: vercel postgres ## important !! edge compatible ##

    github link to auth project:https://github.com/Amith-AG/my-turborepo/tree/main/apps/auth

    explaination:

    • jwt callback:
    callback:{
     async jwt({ account, user, token }) {
          if (account?.provider === 'credentials') {
            const sessionToken = uuidv4()
            const expires = new Date(Date.now() + 60 * 60 * 24 * 30 * 1000)
    
            const session = await PrismaAdapter(db).createSession!({
              userId: user.id!,
              sessionToken,
              expires,
            })
            token.sessionId = session.sessionToken
          }
          return token
        },
    ...
    ...
    }
    
    1. if provider is credential then:
    2. manually create session token and expire data
    3. use prisma adapter to save it into db: PrismaAdapter(db).createSession({sessionData})
    4. then return session token
    • session callback(not neccesary):
    callback:{
    ...
    ...
    session({ session }) {
          if (!session.user) return session
          const user = {
            id: session.user.id,
            name: session.user.name,
            email: session.user.email,
            emailVerified: session.user.emailVerified,
            image: session.user.image,
            role: session.user.role,
          }
          session.user = user
          return session
        },
      },
    

    to add extra info to session data

    • jwt
      jwt: {
        async encode({ token }) {
          return token?.sessionId as unknown as string
        },
    }
    

    token parameter is from jwt callback and this set session token in browser