The base64 encoding + decoding here (link below + base64urlUnescape function) throws 2 bits of the (SHA256) signature into the padding that gets ignored. This results in seemingly different signatures being accepted as valid.
https://github.com/jwtk/njwt/blob/master/index.js#L304
let str = 'koGE1cy2IFhBIPv_XE-kkcWbXu5Pf0hmHoiP0ZfN0b9'; // Modified mac! The correct last character is 8.
str += new Array(5 - str.length % 4).join('=');
str = str.replace(/\-/g, '+').replace(/_/g, '/');
console.log(str); // koGE1cy2IFhBIPv/XE+kkcWbXu5Pf0hmHoiP0ZfN0b9=
str = Buffer.from(str,'base64').toString('base64');
console.log(str); // koGE1cy2IFhBIPv/XE+kkcWbXu5Pf0hmHoiP0ZfN0b8=
Byte value of koGE1cy2IFhBIPv/XE+kkcWbXu5Pf0hmHoiP0ZfN0b9= ends with 00111001 00111101 while the correct koGE1cy2IFhBIPv/XE+kkcWbXu5Pf0hmHoiP0ZfN0b8= ends with 00111000 00111101 where the last 10 bits are padding. Also _ and - suffixes are accepted as valid signatures instead of the correct 8.
Would it make sense to add an extra verification that the base64urlUnescaped value equals the normalized signature to be verified? Or maybe convert the expected signature to the format required by JWT (base64url without padding) for verification?