- 
                Notifications
    You must be signed in to change notification settings 
- Fork 1.3k
Open
Description
Description
The callback to jwt.sign() is executed twice when there is an error Bad "options.issuer" option. The payload already has an "iss" property. I would expect the callback to only be executed once.
Reproduction
// a.mjs
import jwt from "jsonwebtoken";
jwt.sign(
  {
    iss: "bar",
    iat: 1757476476,
  },
  "secret",
  {
    algorithm: "HS256",
    issuer: "foo",
  },
  (err, asyncSigned) => {
    console.log("callback called:", asyncSigned ?? err?.message);
  },
);$> npm init -y && npm add jsonwebtoken
$> node a.mjs
callback called: Bad "options.issuer" option. The payload already has an "iss" property.
callback called: eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJiYXIiLCJpYXQiOjE3NTc0NzY0NzZ9.TkSecbZDocHnjwnuDhQRXNvRkxsERNGBkRc6P0wHlNY
Notice that "callback called" is printed twice, while I would expect it to be printed only once.
Environment
jsonwebtoken 9.0.2 on Darwin 24.6.0 arm64 arm
Other information
It looks like the error is here:
Lines 217 to 225 in bc28861
| Object.keys(options_to_payload).forEach(function (key) { | |
| const claim = options_to_payload[key]; | |
| if (typeof options[key] !== 'undefined') { | |
| if (typeof payload[claim] !== 'undefined') { | |
| return failure(new Error('Bad "options.' + key + '" option. The payload already has an "' + claim + '" property.')); | |
| } | |
| payload[claim] = options[key]; | |
| } | |
| }); | 
Typically, return failure() throws which exits the forEach and the function. But when a callback is provided, it only returns from the forEach. The rest of the keys are checked and the rest of the function still runs.
Metadata
Metadata
Assignees
Labels
No labels