promiseasync-awaitfeathersjsfeathers-authenticationfeathers-hook

FeathersJS: How to cancel the authentication hook using an error from a hook after it


I used app.authenticate on client.
It called the authentication hook in before create hook on server.
I imported from 'feathers-authentication-manage.hook' as verifyHooks.

Before create hook:

app.service('authentication').hooks({
    before: {
      create: [
        authentication.hooks.authenticate(config.strategies),
        async context => {
          const { app, data } = context;

          await app.service('users').find({
            query: {
              usernameUpperCase: data.username.toUpperCase(),
              $limit: 1
            }
          })
          .then(async (user) => {
            await user.data.map(async data => {
              if(!data.isVerified) {
                await console.log('HELLO FROM ABOVE.');
                //await v.validationError('Verify Email. A token link has been sent to your email.');
              }
            });
          })
          .catch(err => v.validationError(err));
        },
        verifyHooks.isVerified()
      ],

The 3 hooks in order were:
1. authentication
2. my hook
3. isVerified() email verify hook from feathers-authentication management

On client, the authenticate promise would be rejected when isVerified() hook activated even if was after the authentication hook.
If I removed the isVerified() hook, the authenticate promise would resolve.

How do I make my hook, the second hook, behave like isVerified() so the authenticate promise on client be rejected?


Solution

  • The first thing is that you are making your life harder by using async/await not as it is intended. The idea is to not having to write all those .then and .catch handlers.

    The .catch handler is also probably where actual issue is. If a .catch (in your case v.validationError(err)) does not reject or throw an error, the promise will resolve successfully. Using async/await the right way and Promise.all to wait for the asynchronous validation steps and then re-throwing the validation error should do it:

    app.service('authentication').hooks({
        before: {
          create: [
            authentication.hooks.authenticate(config.strategies),
            async context => {
              const { app, data } = context;
    
              const user = await app.service('users').find({
                query: {
                  usernameUpperCase: data.username.toUpperCase(),
                  $limit: 1
                }
              });
    
              try {
                await Promise.all(user.data.map(async data => {
                  if(!data.isVerified) {
                    await console.log('HELLO FROM ABOVE.');
                    //await v.validationError('Verify Email. A token link has been sent to your email.');
                  }
                });
              } catch(err) {
                throw v.validationError(err);
              }
            },