validateStrategy(pluginName, strategyName, strategy) {
    const errorPrefix = `[${pluginName}] Strategy ${strategyName}:`;

    if (!isPlainObject(strategy)) {
      throw strategyError.get("invalid_description", errorPrefix, strategy);
    }

    if (!isPlainObject(strategy.methods)) {
      throw strategyError.get("invalid_methods", errorPrefix, strategy.methods);
    }

    const plugin = this._plugins.get(pluginName.toLowerCase());

    // required methods check
    ["exists", "create", "update", "delete", "validate", "verify"].forEach(
      (methodName) => {
        if (!_.isString(strategy.methods[methodName])) {
          throw strategyError.get(
            "invalid_method_type",
            errorPrefix,
            methodName,
            strategy.methods[methodName],
          );
        }

        if (!_.isFunction(plugin.instance[strategy.methods[methodName]])) {
          throw strategyError.get(
            "missing_method_function",
            errorPrefix,
            strategy.methods[methodName],
          );
        }
      },
    );

    // optional methods check
    ["getInfo", "getById", "afterRegister"].forEach((name) => {
      const optionalMethodName = strategy.methods[name];

      if (!_.isNil(optionalMethodName)) {
        if (!_.isString(optionalMethodName)) {
          throw strategyError.get(
            "invalid_method_type",
            errorPrefix,
            name,
            optionalMethodName,
          );
        }

        if (!_.isFunction(plugin.instance[optionalMethodName])) {
          throw strategyError.get(
            "missing_method_function",
            errorPrefix,
            optionalMethodName,
          );
        }
      }
    });

    if (!isPlainObject(strategy.config)) {
      throw strategyError.get("invalid_config", errorPrefix, strategy.config);
    }

    if (typeof strategy.config.authenticator !== "string") {
      throw strategyError.get(
        "invalid_authenticator",
        errorPrefix,
        strategy.config.authenticator,
      );
    } else if (
      !this.authenticators[pluginName] ||
      !this.authenticators[pluginName][strategy.config.authenticator]
    ) {
      throw strategyError.get(
        "unknown_authenticator",
        errorPrefix,
        strategy.config.authenticator,
      );
    }

    for (const optionName of ["strategyOptions", "authenticateOptions"]) {
      const options = strategy.config[optionName];

      if (!_.isNil(options) && !isPlainObject(options)) {
        throw strategyError.get(
          "invalid_option",
          errorPrefix,
          optionName,
          options,
        );
      }
    }

    if (
      !_.isNil(strategy.config.fields) &&
      !Array.isArray(strategy.config.fields)
    ) {
      throw strategyError.get(
        "invalid_fields",
        errorPrefix,
        strategy.config.fields,
      );
    }
  }
Checks if a strategy is well-formed

@param {string} pluginName
@param {string} strategyName
@param {object} strategy
@throws {PluginImplementationError} If the strategy is invalid