1

I am currently experiencing a problem with my login code, where it is supposed to take a username and password, find the corresponding hash in the database, compare them, sign a JWT and return it so that it can be sent back to the user:

async login(username, password): Promise<boolean | void> {
// TODO: Fix typing.
//  Types the return as void currently - should return object.
//  No return at all either, however console.log prints result - check SO when you have time
const dbPwdHash = await this.userRepository.createQueryBuilder('user')
  .select(['user.password', 'user.id'])
  .where('user.username = :username', {username})
  .getOne();
return compare(password, dbPwdHash.password)
  .then(
    (res) => {
      if (res) {
        return sign({ id: dbPwdHash.id }, this.privateKey, { algorithm: 'ES512' }, (err, token) => {
          if (err) {
            return {err};
          } else {
            console.log(token);
            return {data: token};
          }
        });
      }
    },
  )
  .catch(
    (err) => {
      console.log(err);
    },
  );
}

The type definitions type the returns for compare and sign (from bcrypt and jsonwebtoken respectively) are both void by default when using the asynchronous functions with the promise on the compare and the callback on the sign.

The biggest problem I am however experiencing is the fact that in the end nothing gets returned even though a console.log shows that the password is successfully compared and the JWT gets successfully signed. I am sure it is a problem with the sign function as returning the res from the .then() in the compare works fine, however as soon as I add the sign codeblock, nothing returns. However, I'm not sure what exactly is causing that as well as how I'm supposed to respect the typing rules when compare returns <boolean | void> while sign returns <string | void> afaik.

Milan
  • 1,903
  • 17
  • 16
WolfSkin
  • 31
  • 1
  • 9

1 Answers1

0

Calling JWT.sign() with callback passed will execute it asynchronously - which is what you do, this means that the call will return undefined which is what you are returning.

You can either Promisify that call or call JWT.sign synchronously which will then be returned as Promise of a compare(..).then(...) block.

In order to 'Promisify' this callback your return statement would look something like this:

return compare(password, dbPwdHash.password)
        .then(
            (res) => {
                if (res) {
                    return new Promise((resolve, reject) => {
                        sign({id: dbPwdHash.id}, this.privateKey, {algorithm: 'ES512'}, (err, token) => {
                            if (err) {
                                reject(err);
                            } else {
                                console.log(token);
                                resolve({data: token});
                            }

                        });
                    });
                }
                ;
            }
        )
        .catch(
            (err) => {
                console.log(err);
            },
        );

reference: https://github.com/auth0/node-jsonwebtoken#jwtsignpayload-secretorprivatekey-options-callback

Milan
  • 1,903
  • 17
  • 16
  • Won't executing JWT.sign synchronously affect thread performance even though it is inside the promise returned by compare if I understand right? Also, trying to promisify JWT.sign using .then doesn't work at all, since it claims that the .then is not property of string – WolfSkin Mar 10 '19 at 18:06
  • check this for how to convert callback to Promise https://stackoverflow.com/questions/22519784/how-do-i-convert-an-existing-callback-api-to-promises – Milan Mar 10 '19 at 18:09
  • @WolfSkin - I have edited answer with sample on how to convert to promise - let me knwo if it works – Milan Mar 10 '19 at 18:20
  • Other than the fact that the typing is still broken (and I'll probably have to just ignore it), it works perfectly! – WolfSkin Mar 10 '19 at 18:27
  • @WolfSkin - Great I suggest you edit your question a bit so that it's clear it's the issue with calling sign on jwt) - I assume more people would run into this problem, regardless of using typescript. – Milan Mar 10 '19 at 18:37