DEV Community


Posted on

Extending Strapi plugins 🚀 Ultimate guide 👨‍💻

Hey folks! 🤙

You've chosen the right post if you're keen on flexing your JavaScript muscles and going on a coding adventure with Strapi. Strapi, the open-source CMS powerhouse, comes with a plugin system that is all about flexibility and adaptability, and today, we're going to nudge it a bit to suit our unique requirements. 🧗‍♂️

The Mission 🎯

Our goal was simple but crucial - to ensure that users don't keep leaning on their old faithfuls when resetting their passwords. The good news is that Strapi provides a plugin system that we can tweak to ensure users always choose new passwords.

The Preparation 📝

Before we dive into the code, here are a few important points to keep in mind:

We can apply this approach to various methods declared in Strapi plugins. Whether it's register, forgotPassword, resetPassword, user or any other method within the @node_modules/@strapi/plugin-<name-of-the-plugin> (in our case users-permissions), you can bend it to your will.

To extend a Strapi plugin, create a new folder inside src/extensions/. This is where you'll make your changes without disturbing the core plugin code.

In the new folder, add a file named strapi-server.js or strapi-server.ts and place your custom code there. Now, let's see how this works in practice!

The Code 🚀

Check out the final solution below:

const utils = require('@strapi/utils');

module.exports = (plugin) => {

    const { ValidationError } = utils.errors;
    const originalControllers = {
        callback: plugin.controllers.auth.callback,
        resetPassword: plugin.controllers.auth.resetPassword,

    plugin.controllers.auth.resetPassword = async (ctx) => {
        const { password, passwordConfirmation } = ctx.request.body;
        // Fetch user
        const user = await strapi
            .findOne({ resetPasswordToken: ctx.params.code });

        // Compare old and new passwords
        const validPassword = await strapi.plugins['users-permissions'].services.user.validatePassword(password, user.password);

        if (validPassword) {
            throw new ValidationError('Passwords cannot match previous passwords');

        await originalControllers.resetPassword(ctx);

    return plugin;


Enter fullscreen mode Exit fullscreen mode

Dissecting the Code 🧐

Let's take a magnifying glass to this code snippet:

  1. We're using Strapi's utility library, which has a plethora of helpful tools.

  2. We're exporting a function that accepts a plugin as an argument.

  3. Within this function, we're preserving the original controllers for callback and resetPassword.

  4. Then, we're defining a new resetPassword function. This doesn't discard the original function; rather, it only executes after we've added our own validation.

  5. In this new function, we're retrieving the user requesting the password reset.

  6. We're then comparing the new password against the old one with Strapi's built-in password validation method.

  7. If the new password is the same as the old one, we're raising a validation error.

  8. Finally, we execute the original resetPassword function, allowing Strapi to perform its usual magic.

By extending the resetPassword method this way, we add our custom behaviour while maintaining the core Strapi functionality intact. It's akin to a skillful remix of a classic song - you maintain the original melody while adding your unique spin! 🎵

That's all, folks! Get out there and make Strapi work for you. As always, remember to test your code thoroughly to ensure it behaves as expected. Happy coding! 👨‍💻👩‍💻


Top comments (0)