Search code examples
typescriptnext.jsnext-authcredential-providers

Argument of type 'string | undefined' is not assignable to parameter of type 'string | Buffer' (Next Auth & TS)


I'm encountering the following TypeScript error:

"Argument of type 'string | undefined' is not assignable to parameter of type 'string | Buffer'."

I'm integrating NextAuth with my Next.js 14 application and configuring login credentials to compare passwords during login. However, I'm facing this error specifically with the input password in the following line:

  const passwordOk =
          existingUser && bcrypt.compareSync(password, existingUser.password)

and this is the full options file

import CredentialsProvider from "next-auth/providers/credentials"
import type { NextAuthOptions } from "next-auth"
import connectMongoDB from "@/lib/mongodb"
import bcrypt from "bcrypt"
import User from "@/models/user"

export const authOptions: NextAuthOptions = {
  // Configure one or more authentication providers
  providers: [
    CredentialsProvider({
      name: "Credentials",
      credentials: {
        // email: { label: "Email", type: "email", placeholder: "email" },
        // password: { label: "Password", type: "password" },
        email: {},
        password: {},
      },
      async authorize(credentials, req) {
        const email = credentials?.email
        const password = credentials?.password
        // Add logic here to look up the user from the credentials supplied
        await connectMongoDB()
        const existingUser = await User.findOne({ email })
        const passwordOk =
          existingUser && bcrypt.compareSync(password, existingUser.password)

        if (passwordOk) {
          // Any object returned will be saved in `ser` property of the JWT
          return existingUser
        } else {
          // If you return null then an error will be displayed advising the user to check their details.
          return null

          // You can also Reject this callback with an Error thus the user will be sent to the error page with the error message as a query parameter
        }
      },
    }),
  ],
}

I have tried to assign this type manually on the password but didn't work

        const password: string | Buffer = credentials?.password

I also tried this

const passwordOk =
          existingUser &&
          password &&
          bcrypt.compareSync(password, existingUser.password)

and the error disappeared, but I'm not sure if it is a best practice


Solution

  • credentials?.password might return undefined because of Optional chaining ?. and compareSync couldn't be evaluated with an undefined as a first parameter, hence, you are seeing this error.

    From MDN

    The optional chaining (?.) operator accesses an object's property or calls a function. If the object accessed or function called using this operator is undefined or null, the expression short circuits and evaluates to undefined instead of throwing an error.

    Since passwordOk will be affected by password value, it's recommended to check for its value (and for the email as well) before continuing with the excution, though, a Guard Clause would be great here:

    const email = credentials?.email;
    const password = credentials?.password;
    if (!email || !password) return;
    // rest of the code
    

    This should remove the error.

    Another solution that I don't really recommend in such cases (due to somehow breaking the typescript checking system) is to use non-null assertion operator and the syntax is pretty easy, simply postfix your password with exclamation mark, i.e. credentials.password! this tells typescript that you are pretty sure that this expression will return a value and will never be null or undefined.