code: function exchangePassword(client, username, password, scope, body, authInfo, done) {
      if (!client || !client.id) {
          return done(new common.errors.UnauthorizedError({
              message: common.i18n.t('errors.middleware.auth.clientCredentialsNotProvided')
          }), false);
      }
  
      // Validate the user
      return models.User.check({email: username, password: password})
          .then(function then(user) {
              return authUtils.createTokens({
                  clientId: client.id,
                  userId: user.id
              });
          })
          .then(function then(response) {
              web.shared.middlewares.api.spamPrevention.userLogin()
                  .reset(authInfo.ip, username + 'login');
  
              return done(null, response.access_token, response.refresh_token, {expires_in: response.expires_in});
          })
          .catch(function (err) {
              done(err, false);
          });
  }
docs: We are required to pass in authInfo in order to reset spam counter for user login