Node-jsonwebtoken: util.promisify(jwt.sign) doesn't accept options object

Created on 23 Mar 2020  Â·  3Comments  Â·  Source: auth0/node-jsonwebtoken

By submitting an Issue to this repository, you agree to the terms within the Auth0 Code of Conduct.

Description

Turning the jwt.sign callback into a promise with the built in node util.promisify() function doesn't accept an options object as the third argument

Reproduction

CODE

import jwt  from 'jsonwebtoken';
import { promisify } from 'util';
const asyncSign = promisify(jwt.sign);

export async function encodeJWT(payload: string | object | Buffer): Promise<unknown> {
  return await asyncSign(payload, JWT_SECRET, { expiresIn: '' });
}

ERROR

    return new TSError(diagnosticText, diagnosticCodes)
           ^
TSError: ⨯ Unable to compile TypeScript:
src/lib/hash.ts:40:47 - error TS2554: Expected 2 arguments, but got 3.

40   return await asyncSign(payload, JWT_SECRET, { expiresIn: '' });
                                                 ~~~~~~~~~~~~~~~~~

Environment

Package.json

    "@types/jsonwebtoken": "^8.3.8",
    "jsonwebtoken": "^8.5.1",
    "typescript": "^3.8.3"

Mac OS X Catalina

Visual Studio Code

TypeScript 3.8

jsonwebtoken 8.5

node v12.14.0

Update

Fix for anyone else with this issue

Wrap callback in a promise

Typescript

export function encodeJWT(payload: string | object | Buffer): Promise<unknown> {
  return new Promise((resolve, reject) => {
    jwt.sign(payload, JWT_SECRET, { expiresIn: '30d' }, (err, token) => {
      if (err) return reject(err);
      else return resolve(token);
    });
  });
}

Javascript

export function encodeJWT(payload) {
  return new Promise((resolve, reject) => {
    jwt.sign(payload, JWT_SECRET, { expiresIn: '30d' }, (err, token) => {
      if (err) return reject(err);
      else return resolve(token);
    });
  });
}

Most helpful comment

I was able to reproduce. The issue seems to be the overloading of the sign method and promisify basically picking the "first" instance of the overloaded sign method that appears in the definition https://github.com/DefinitelyTyped/DefinitelyTyped/blob/da534110efb3088d245ed9894cd28ef71191f6f2/types/jsonwebtoken/index.d.ts#L140.

Beside the workaround you've suggested, you could also try this:

const asyncSign = (
  payload: string | Buffer | object,
  secretOrPrivateKey: Secret,
  options: SignOptions
) => promisify(sign);

This will effectively act as a "hint" for promisify to use the correct method signature.

All 3 comments

I was able to reproduce. The issue seems to be the overloading of the sign method and promisify basically picking the "first" instance of the overloaded sign method that appears in the definition https://github.com/DefinitelyTyped/DefinitelyTyped/blob/da534110efb3088d245ed9894cd28ef71191f6f2/types/jsonwebtoken/index.d.ts#L140.

Beside the workaround you've suggested, you could also try this:

const asyncSign = (
  payload: string | Buffer | object,
  secretOrPrivateKey: Secret,
  options: SignOptions
) => promisify(sign);

This will effectively act as a "hint" for promisify to use the correct method signature.

Hello there @svnty :). Yet another solution is to do:
const signToken = promisify<object, Secret, SignOptions>(sign); signToken(payload, 'secret', jwtOptions);

This works for me
promisify(sign)({ ...payload }, cert, { algorithm: config.jwt.algorithm });
Append the sign options to the payload, it will work

Was this page helpful?
0 / 5 - 0 ratings

Related issues

AndreOneti picture AndreOneti  Â·  3Comments

Sir-hennihau picture Sir-hennihau  Â·  4Comments

usamamashkoor picture usamamashkoor  Â·  4Comments

shea256 picture shea256  Â·  3Comments

rynbyjn picture rynbyjn  Â·  5Comments