Reputation: 543
I am trying to convert a mern application to nextjs but I'm having trouble with next-auth. I am creating a user with email and password in a separate registration form and if I go to the login form and on the AuthOptions page, if I comment out the callbacks at the bottom, the email and password login works.
The google provider works with no problem, saivng the user in the mongoDB if it is not there.
I if I do not comment out the callbacks and try to log in using email and password, it runs the credentials profile part but then tries to run the callbacks. Is there a better wey. I have struggled to get this to work using one tutorial to set up to googleProvider and a separate one to set up the credentialsProvider, but I cannot get them to work together.
Here is my /api/auth/[...nextauth]/route.js
import { authOptions } from "@/utils/authOptions";
import NextAuth from "next-auth";
const handler = NextAuth(authOptions);
export { handler as GET, handler as POST };
And this is my authOptions file:
import GoogleProvider from "next-auth/providers/google";
import CredentialsProvider from "next-auth/providers/credentials";
import connectDB from "@/lib/database";
import User from "@/models/User";
import bcrypt from "bcryptjs";
export const authOptions = {
providers: [
CredentialsProvider({
name: "Credentials",
credentials: {
email: {
label: "email:",
type: "email",
name: "email",
placeholder: "your-email",
},
password: {
label: "password:",
type: "password",
name: "password",
placeholder: "your-password",
},
},
async authorize(credentials) {
try {
const foundUser = await User.findOne({
email: credentials.email,
}).lean();
if (foundUser) {
console.log("found user ", foundUser);
console.log("User Exists");
const match = await bcrypt.compare(
credentials.password,
foundUser.password
);
if (match) {
console.log("Good Pass");
delete foundUser.password;
foundUser["role"] = "Unverified Email";
return foundUser;
}
}
} catch (error) {
console.log(error);
}
return null;
},
}),
GoogleProvider({
clientId: process.env.GOOGLE_CLIENT_ID,
clientSecret: process.env.GOOGLE_CLIENT_SECRET,
authorization: {
params: {
prompt: "consent",
access_type: "offline",
response_type: "code",
},
},
}),
],
callbacks: {
async signIn({ profile }) {
await connectDB;
const userExists = await User.findOne({ email: profile.email });
if (!userExists) {
const username = profile.name.slice(" ");
await User.create({
firstName: username[0],
lastName: username[1],
email: profile.email,
image: profile.picture,
});
}
return true;
},
async session({ session }) {
const user = await User.findOne({ email: session.user.email });
session.user.id = user._id.toString();
return session;
},
},
};
Upvotes: 0
Views: 65
Reputation: 543
After some searching, I found a tutorial that did pretty much what I wanted. I had to edit it a litlte but got it working.
Here is my update authOptions.js file:
import GoogleProvider from "next-auth/providers/google";
import CredentialsProvider from "next-auth/providers/credentials";
import connectDB from "@/lib/database";
import User from "@/models/User";
import bcrypt from "bcryptjs";
import { validateUsername } from "@/helpers/validation";
export const authOptions = {
providers: [
CredentialsProvider({
name: "credentials",
credentials: {
email: {
label: "email:",
type: "email",
name: "email",
placeholder: "your-email",
},
password: {
label: "password:",
type: "password",
name: "password",
placeholder: "your-password",
},
},
async authorize(credentials) {
try {
await connectDB();
const user = await User.findOne({ email: credentials.email });
if (!user) {
return null;
}
const passwordsMatch = await bcrypt.compare(
credentials.password,
user.password
);
if (!passwordsMatch) {
return null;
}
return user;
} catch (error) {
console.log("Error:", error);
}
},
}),
GoogleProvider({
clientId: process.env.GOOGLE_CLIENT_ID,
clientSecret: process.env.GOOGLE_CLIENT_SECRET,
}),
],
session: {
strategy: "jwt",
},
callbacks: {
async signIn({ user, account }) {
if (account.provider === "google") {
try {
const { name, email, image } = user;
await connectDB();
const userExists = await User.findOne({ email });
if (userExists) {
return userExists;
}
const nameArray = name.split(" ");
let tempUsername =
nameArray[0].toLowerCase() + nameArray[1].toLowerCase();
let newUsername = await validateUsername(tempUsername);
const newUser = new User({
firstName: nameArray[0],
lastName: nameArray[1],
email: email,
username: newUsername,
googleAvatar: image,
avatarType: "google",
});
const res = await newUser.save();
if (res.status === 200 || res.status === 201) {
console.log(res);
return res;
}
} catch (err) {
console.log(err);
}
}
//console.log("user - 82 ", user);
return user;
},
async jwt({ token, user }) {
if (user) {
const userInfo = await User.findOne({ email: user.email }).lean();
token.userId = userInfo._id;
token.email = userInfo.email;
token.firstName = userInfo.firstName;
token.lastName = userInfo.lastName;
token.username = userInfo.username;
token.avatar =
userInfo.avatarType === "google"
? userInfo.googleAvatar
: userInfo.avatar;
token.avatarType = userInfo.avatarType;
token.isAdmin = userInfo.isAdmin;
}
console.log("token ", token);
return token;
},
async session({ session, token }) {
if (session.user) {
session.user.userId = token.userId;
session.user.email = token.email;
session.user.firstName = token.firstName;
session.user.lastName = token.lastName;
session.user.username = token.username;
session.user.avatar =
token.avatarType === "googleAvatar"
? token.googleAvatar
: token.avatar;
session.user.avatarType = token.avatarType;
session.user.isAdmin = token.isAdmin;
}
console.log(session);
return session;
},
},
};
Upvotes: 0