Forgot strapi password v4 returns an error 400 how to fix this

Here is the test here

Hey @Rodritsms

Check if in the configuration “Users & Permissions plugin” > Public > Permissions > Users permissions you allowed the forgotPassword method.

I believe it’s because the format of your post is not as per their documentation:

Ref:

I have the same problem i went to the code source of the forgot controller then found something weird!

js
try {
      // Send an email to the user.
      await strapi
        .plugin('email')
        .service('email')
        .send({
          to: user.email,
          from:
            settings.from.email || settings.from.name
              ? `${settings.from.name} <${settings.from.email}>`
              : undefined,
          replyTo: settings.response_email,
          subject: settings.object,
          text: settings.message,
          html: settings.message,
        });
    } catch (err) {
      throw new ApplicationError(err.message);
    }

and if you console.log(settings) you will find that they dont grab infromation from the provider configuration file /config/plugins.js
the settings will look like this:

{
  from: { name: 'Administration Panel', email: 'no-reply@strapi.io' },
  response_email: '',
  object: 'Reset password',
  message: '<p>We heard that you lost your password. Sorry about that!</p>\n' +
    '\n' +
    '<p>But don’t worry! You can use the following link to reset your password:</p>\n' +
    '<p>?code=498ffda73fee30286f2fcfc4e31e57ad9cfcd074ef657e8ec23494e72d33fdb02626e5715036894dd5fb0c2ee8c1a4a94fbe587c0bf153e986c8baf74ccc2a0a</p>\n' +
    '\n' +
    '<p>Thanks.</p>'
}

so instead hardcode the from and replyTo properties with the email you used with the provider !

Hello, in my case I solved it by making a new email service, with my templates (email designer) like this:
module.exports = {
async sendEmail(to, templateId, data) {
try {
await strapi
.plugin(‘email-designer’)
.service(‘email’)
.sendTemplatedEmail(
{
// required
to: to,
from: process.env.DEFAULTFROM,
// optional array of files
attachments: [],
},
{
// required - Ref ID defined in the template designer (won’t change on import)
templateReferenceId: templateId,
},
{ …data }
);
} catch (err) {
strapi.log.debug(':tv:: ', err);
return ctx.badRequest(null, err);
}
},
};

and i call the service in my controller like this, i make a overwrite the code:
this is the part of the service:
await EmailService.sendEmail(
user.email,
idioma === “en” ? process.env.PASSWORD_EN : process.env.PASSWORD_ES,
{TOKEN: resetPasswordToken, URL: URL }
);

and this is the code:
// FORGOT PASSWORD
(plugin.controllers.auth.forgotPassword = async (ctx) => {
// const { email } = await validateForgotPasswordBody(ctx.request.body);
const { email, idioma } = ctx.request.body;
// console.log(email);

  const pluginStore = await strapi.store({
    type: "plugin",
    name: "users-permissions",
  });

  const emailSettings = await pluginStore.get({ key: "email" });
  const advancedSettings = await pluginStore.get({ key: "advanced" });

  // Find the user by email.
  const user = await strapi
    .query("plugin::users-permissions.user")
    .findOne({ where: { email: email.toLowerCase() } });

  if (!user || user.blocked) {
    return ctx.send({ ok: true });
  }

  // Generate random token.
  const userInfo = await sanitizeUser(user, ctx);

  const resetPasswordToken = crypto.randomBytes(64).toString("hex");
  const URL = advancedSettings.email_reset_password;

  const resetPasswordSettings = _.get(
    emailSettings,
    "reset_password.options",
    {}
  );

  const emailObject = await getService("users-permissions").template(
    resetPasswordSettings.object,
    {
      USER: userInfo,
    }
  );

  // NOTE: Update the user before sending the email so an Admin can generate the link if the email fails
  await getService("user").edit(user.id, { resetPasswordToken });

  // Send an email to the user.
  // await strapi.plugin("email").service("email").send(emailToSend);
  await EmailService.sendEmail(
    user.email,
    idioma === "en" ? process.env.PASSWORD_EN : process.env.PASSWORD_ES,
    {TOKEN: resetPasswordToken, URL: URL }
  );
  
  return resetPasswordToken;
});


ROUTE:
plugin.routes[“content-api”].routes.push({
method: “POST”,
path: “/auth/forgotPassword”,
handler: “auth.forgotPassword”,
config: {
prefix: “”,
},
});

@sandovaljr first of all thanks for the solution but I’m having an issue in implementing your code correctly
can you please edit your solution in proper code with a file name and their path it’ll be beneficial to me
please …!!! I would appreciate your help