How can i create a simple reset password using next auth Credential provider with mongo db
i have user schema like this
const userSchema = new mongoose.Schema<UserSchemaType>(
{
name: { type: String, required: true },
email: { type: String, required: true, unique: true },
password: { type: String, required: true },
img: { type: String, required: true },
isAdmin: { type: Boolean, required: true, default: false },
},
{
timestamps: true,
}
);
my next auth look like this
providers: [
CredentialsProvider({
async authorize(credentials) {
await db.connect();
const user = await User.findOne({
email: credentials.email,
});
if (user && bcryptjs.compareSync(credentials.password, user.password)) {
return {
_id: user._id,
name: user.name,
email: user.email,
image: user.img,
isAdmin: user.isAdmin,
};
}
throw new Error('Invalid email or password');
},
}),
],
});
is there a simple example for implementing reset password with the next auth
From the docs - https://next-auth.js.org/providers/credentials
The functionality provided for credentials based authentication is
intentionally limited to discourage use of passwords due to the
inherent security risks associated with them and the additional
complexity associated with supporting usernames and passwords.
Probably you can use the Email Provider and customise if you really want this feature.
https://next-auth.js.org/configuration/providers/email
Related
I need to pass additional parameters to signIn function using next-auth in a NextJs project.
Here is what I tried.
<button
onClick={() =>
signIn(providers.facebook.id, { userType: "customer" })
}
>
<img src="images/facebook.svg" className="w-5 h-5" />
</button>
[...nextAuth].js code
import NextAuth from "next-auth";
import dbConnect from "../../../lib/dbConnect";
import CredentialsProvider from "next-auth/providers/credentials";
import User from "../../../models/User";
import brcypt from "bcryptjs";
import GoogleProvider from "next-auth/providers/google";
import FacebookProvider from "next-auth/providers/facebook";
import InstagramProvider from "next-auth/providers/instagram";
dbConnect();
export default NextAuth({
session: {
strategy: "jwt",
},
secret: process.env.NEXTAUTH_SECRET,
//The providers are the authentication method
providers: [
CredentialsProvider({
// The name to display on the sign in form (e.g. 'Sign in with...')
name: "Credentials",
// The credentials is used to generate a suitable form on the sign in page.
// You can specify whatever fields you are expecting to be submitted.
// e.g. domain, username, password, 2FA token, etc.
// You can pass any HTML attribute to the <input> tag through the object.
credentials: {
email: { label: "Email", type: "email" },
password: { label: "Password", type: "password" },
},
async authorize(credentials, req) {
try {
const email = credentials.email;
const password = credentials.password;
const user = await User.findOne({ email: email });
if (!user) {
return null;
}
if (user) {
let allow = await signInUser({ password, user });
if (allow == true) {
return user;
} else {
return null;
}
}
} catch (error) {
return null;
}
},
}),
GoogleProvider({
clientId: process.env.GOOGLE_CLIENT_ID,
clientSecret: process.env.GOOGLE_CLIENT_SECRET,
authorizationUrl:
"https://accounts.google.com/o/oauth2/v2/auth?prompt=consent&access_type=offline&response_type=code",
}),
FacebookProvider({
clientId: process.env.FACEBOOK_CLIENT_ID,
clientSecret: process.env.FACEBOOK_CLIENT_SECRET,
authorization: {
params: {
userType: "customer" || "admin",
},
},
}),
InstagramProvider({
clientId: process.env.INSTAGRAM_CLIENT_ID,
clientSecret: process.env.INSTAGRAM_CLIENT_SECRET,
}),
],
pages: {
signIn: "/login",
},
database: process.env.MONGODB_URI,
callbacks: {
async jwt(token, profile) {
console.log("jwt token>>>>", token);
console.log("jwt profile>>>>", profile);
return token;
},
async session({ session, user, token }) {
if (token) {
const name = token.token.user.name;
const email = token.token.user.email;
const image = token.token.user.image;
const platform = token.token.account.provider;
handleUser(name, email, image, platform);
}
return token.token.token;
},
},
});
const signInUser = async ({ password, user }) => {
let allow = true;
if (!password) {
allow = false;
}
const isMatch = await brcypt.compare(password, user.password);
if (!isMatch) {
allow = false;
}
return allow;
};
async function handleUser(name, email, image, platform) {
console.log("Handle User>>>>>", name);
console.log("Handle email>>>>>", email);
console.log("Handle image>>>>>", image);
console.log("Handle platform>>>>>", platform);
}
Inside the callbacks function I tried logging token & profile. The additional params I passed is not being sent.
What is the right way to achieve this in Next.js?
You can find an article on the GitHub discussion section for next-auth here. The general gist of the answer is that you specify additional custom parameters in the Google Provider parameter (as below). There are other steps, but overall they appear to have solved it. Hope this helps.
GoogleProvider({
clientId: process.env.GOOGLE_CLIENT_ID,
clientSecret: process.env.GOOGLE_CLIENT_SECRET,
authorization: {
params: {
prompt: "consent",
access_type: "offline",
response_type: "code",
userType: "user" || "admin", <-- THIS ONE
},
},
}),
Did someone encounter similar errors when trying to decode your next-auth.session-token on jwt.io? I followed a video and tried copy my session token to jwt.io to see it, but all i get is an error saying "Invalid signature"
What did i miss here?
[...nextauth].tsx file
import NextAuth, { NextAuthOptions } from "next-auth";
import CredentialsProvider from "next-auth/providers/credentials";
const authOptions: NextAuthOptions = {
session: {
strategy: "jwt",
},
providers: [
CredentialsProvider({
type: "credentials",
credentials: {},
authorize(credentials, req) {
const { email, password } = credentials as {
email: string;
password: string;
};
//Perform your login logic here
//Find out user from db
if (email !== "john#gmail.com" || password !== "1234") {
throw new Error("Invalid credentials");
}
//If everything is fine
return { id: "1234", name: "John Doe", email: "john#gmail.com" };
},
}),
],
pages: {
signIn: "/auth/signin",
},
};
export default NextAuth(authOptions);
Cookie image
jwt io image
I try to get credentials auth with next-auth, but I have no experience to use it and whatever I do, i get following message:
[next-auth][error][callback_credentials_jwt_error] Signin in with credentials is only supported if JSON Web Tokens are enabled
https://next-auth.js.org/errors#callback_credentials_jwt_error
This is my src/pages/api/auth/[...nextauth].js file.
import NextAuth from 'next-auth'
import Providers from 'next-auth/providers'
import User from "#models/User"
const options = {
NEXTAUTH_URL:process.env.NEXTAUTH_URL,
providers: [
Providers.Credentials({
// The name to display on the sign in form (e.g. 'Sign in with...')
name: 'Avista',
// The credentials is used to generate a suitable form on the sign in page.
// You can specify whatever fields you are expecting to be submitted.
// e.g. domain, username, password, 2FA token, etc.
credentials: {
email: {label: "Email", type: "text"},
password: {label: "Password", type: "password"}
},
authorize: async (credentials) => {
// Add logic here to look up the user from the credentials supplied
// const user = {id: 1, name: 'J Smith', email: 'jsmith#example.com'}
const user = await User.findOne()
console.log("Данные входа", credentials)
if (user) {
// Any object returned will be saved in `user` property of the JWT
return Promise.resolve(user)
} else {
// If you return null or false then the credentials will be rejected
return Promise.resolve(null)
// You can also Reject this callback with an Error or with a URL:
// return Promise.reject(new Error('error message')) // Redirect to error page
// return Promise.reject('/path/to/redirect') // Redirect to a URL
}
}
}),
Providers.Email({
server: {
host: process.env.EMAIL_SERVER_HOST,
port: process.env.EMAIL_SERVER_PORT,
auth: {
user: process.env.EMAIL_SERVER_USER,
pass: process.env.EMAIL_SERVER_PASSWORD
}
},
from: process.env.EMAIL_FROM
}),
],
// A database is optional, but required to persist accounts in a database
database: process.env.MONGO_URI,
secret: process.env.JWT_SIGNING_PRIVATE_KEY,
},
}
I don't know what I do wrong.
try adding this to your [...nextauth].js page
session: {
jwt: true,
// Seconds - How long until an idle session expires and is no longer valid.
maxAge: 30 * 24 * 60 * 60, // 30 days
},
read more about the options here: https://next-auth.js.org/configuration/options#jwt
This might be useful for someone else.
You need to specify that you want to use the jwt auth style.
Make options.session to be:
{ jwt: true }
If you using next-auth version 4, you should instead do:
{ strategy: 'jwt'}
Add this after providers: []
callbacks: {
jwt: async ({ token, user }) => {
user && (token.user = user)
return token;
},
session: async ({ session, token }) => {
session.user = token.user
return session;
}
},
secret: "secret",
jwt: {
secret: "ksdkfsldferSDFSDFSDf",
encryption: true,
},
I'm trying to register users using node and mongo but I get this ValidationError:
unhandledPromiseRejectionWarning: ValidationError: user validation failed: password: Path password is required., username: Path username is required., email: Path email is required.
this is my signup function.
exports.signup = async function (request, res, next) {
try {
let user = await db.User.create(request.body);
console.log(user);
let { id,email,username } = user;
let token = jwt.sign({
id,
email,
username
},
process.env.SECRET_KEY
);
return res.status(200).json({
id,
username,
token
})
} catch (err) {
if (err.code === 11000) {
err.message = "sorry, username/email are token";
}
return next({
status: 400,
message: err.message
})
}
this is my user model
const userSchema = new mongoose.Schema({
email: {
type: String,
required: true,
unique: true,
},
username: {
type: String,
required: true,
unique: true
},
password: {
type: String,
required: true,
},
profileImageUrl: {
type: String,
},
messages:[{
type:mongoose.Schema.Types.ObjectId,
ref:'Message'
}]
})
userSchema.pre('save', async function (next) {
try {
if (!this.isModified('password')) {
return next();
}
let hashedPassword = await bcrypt.hash(this.password, 10);
this.password = hashedPassword;
return next();
} catch (err) {
return next(err);
}
});
const User = mongoose.model("user", userSchema);
module.exports = User;
NOTE: I'm using Postman to test this.
So yeah I found the problem. the fields are required so if you try to insert a new user with empty fields you get that error. The fields were empty because The 'body-parser' middleware only handles JSON and urlencoded data, not multipart. So I had to change my index file to
app.use(bodyParser.urlencoded({
extended: true
}));
I also changed the content type in Postman to "X-www-form-urlencoded". Now the request body is populated and the user is inserted correctly
I also faced this error.
In your user model remove required:true in all fields like this:
email: {
type: String,
unique: true
}
I have a Meteor application with the following fixtures code:
/imports/startup/server/fixtures.js
import { Meteor } from 'meteor/meteor'
import { Accounts } from 'meteor/accounts-base'
if(Meteor.users.find().count === 0) {
const users = [
{username: "admin", email: "admin#testing.demo", profile: { name: "Admin" }, roles: ["admin"]},
{username: "school", email: "school#testing.demo", profile: { name: "School Name" }, roles: ["school"]},
{username: "teacher", email: "teacher#testing.demo", profile: { name: "Teacher" }, roles:["teacher"]}
]
for(let user of users) {
Accounts.createUser({
username: user.username,
email: user.email,
password: "123456",
profile: {
name: user.profile.name,
},
roles: user.roles
})
}
}
On starting up my project all the accounts are created successfully except none of them have the roles field. What am I doing wrong?
What you are doing wrong is that you pass options into the function that are not accepted by it. createUser options only accepts username, email, password and profile. You should study the docs, meteors API is very well documented.
Now, to set the user roles you have a couple of options, one of them would be use the _id of the newly created user, which is returned by createUser and then set the roles like so:
const userId = Accounts.createUser({
username: user.username,
email: user.email,
password: "123456",
profile: {
name: user.profile.name,
});
Roles.addUsersToRoles(userId, user.roles)
assuming that this is server side code. On the client this won't work. You could also set the roles directly using a Meteor.users.update(); call or fiddle around with Accounts.onCreateUser callback, which is very nice for manipulating everything that you pass into createUser. Hope that helps.