Search code examples
next.jsprismanext-auth

How to use next-auth using ldap and prisma


i am using next-auth with ldap to authenticate user name and password. i am able to log/authenticate the user using username and password. but when i can't create user using prisma as await is not allowed inside promise. this is my [...next-auth].js

`

const ldap = require("ldapjs");
import NextAuth from "next-auth";
import CredentialsProvider from "next-auth/providers/credentials";
import { PrismaClient } from "@prisma/client";

const url = `ldap://${process.env.LDAP_SERVER}`;
const prisma = new PrismaClient();

export default NextAuth({
  providers: [
    CredentialsProvider({
      name: "LDAP",
      credentials: {
        username: { label: "DN", type: "text", placeholder: "" },
        password: { label: "Password", type: "password" },
      },
      authorize: async (credentials, req) => {
        // You might want to pull this call out so we're not making a new LDAP client on every login attemp
        const client = ldap.createClient({
          url: url,
        });

        return new Promise((resolve, reject) => {
          client.bind(
            `${credentials.username}@${process.env.LDAP_DOMAIN}`,
            credentials.password,
            (error) => {
              if (error) {
                console.log("Wrong email or password.");
                reject("Wrong email or password.");
              } else {
                console.log("Successfully Logged In");
                resolve({
                  username: credentials.username,
                  password: credentials.password,
                });
              }
              const filter = `(sAMAccountName=${credentials.username})`;

              client.search(
                process.env.LDAP_BASE_DN,
                {
                  filter,
                  scope: "sub",
                  attributes: [
                    "mail",
                    "employeeid",
                    "title",
                    "name",
                    "division",
                    "department",
                    "section",
                  ],
                },
                (err, results) => {
                  if (err) {
                    reject(`User ${username} LDAP search error`);
                  }

                  const entries = [];

                  results.on("searchEntry", (entry) => {
                    entries.push(entry.object);
                  });

                  results.on("error", (err) => {
                    reject("LDAP SEARCH error");
                  });

                  results.on("end", (result) => {
                    if (entries.length == 0) {
                      reject("Something went wrong. Please try again. (AD)");
                    }

                    console.log({ entries });

                    const searchResult = JSON.stringify(entries[0]);
                    const adEmployee = JSON.parse(searchResult);
                    const empId = adEmployee?.employeeID;
                    const name = adEmployee.name;

                    console.log(empId);

                    const newUser= await prisma.user.findUnique({
                      where:{
                        oracleId:oracleId
                      }
                    })

                    if(!newUser){
                      await prisma.user.create({
                        data:{
                          oracleId:empId,
                          fullName:name
                        }
                      })
                    }
                      
                  });
                }
              );
            }
          );
        });
      },
    }),
  ],
  pages: {
    signIn: "/auth/sign-in",
  },
  callbacks: {
    jwt: async ({ token, user }) => {
      if (user) {
        token.username = user.username;
        token.password = user.password;
      }
      return token;
    },
    session: async ({ session, token }) => {
      if (token) {
        session.id = token.id;
        session.username = token.username;
      }
      // console.log(token);
      return session;
    },
  },
  debug: process.env.NODE_ENV === "development",
  secret: process.env.NEXTAUTH_SECRET,
  jwt: {
    secret: process.env.NEXTAUTH_SECRET,
    encryption: true,
  },
});

`

await is not allowed inside promise, where should i call prisma. Thanks


Solution

  • For this u need to use API endpoint (as prisma is used on server side and cannot be used on client side especially when you pass db url from env also not shown on frontend), your create for example /api/register where:

    import { PrismaClient } from '@prisma/client';
    import dotenv from 'dotenv' 
    dotenv.config();
    const prisma = new PrismaClient();
    
    const Handler = async (
        req,
        res
    ) => {
        await prisma.$connect()
        const users = await prisma.user.findMany()
        //check if user u add is already in db
        //if not then
            try {
                savedUser = await prisma.user.create({ data: new_user });
                await prisma.$disconnect()
            } catch (error: any) {
                await prisma.$disconnect()
                // show db error
                return res.status(501).json({message: error.message})
            }
            res.status(200).json({ message: 'User added to db ' + savedUser.name });
    
    }
    

    this is just a simple explanation of what you need to do to make it work, you may add some safety:

    const { username, password } = req.body
    if (req.method !== 'POST') {
        return res.status(405).json({ message: 'Method not allowed' });
        
    }
    
    if (!username || !password) {
        return res.status(400).json({ message: 'Username and password are required' });
    }
    

    then u call api endpoint:

        const response = await axios.post(
            LOGIN_URL,
            JSON.stringify({ username, password }),
            {
                headers: { 'Content-Type': 'application/json' },
                withCredentials: true
            }
        )
    

    where LOGIN_URL could be /api/register