I'm encountering an issue in my Node.js (20.5.1) application related to JSON Web Token (JWT) verification using RSA key pairs. The error message is as follows:
[16:39:56.959] FATAL (26460): invalid signature
err: {
"type": "JsonWebTokenError",
"message": "invalid signature",
"stack":
JsonWebTokenError: invalid signature
at U:\Coding\MCShop-API\node_modules\jsonwebtoken\verify.js:171:19
at getSecret (U:\Coding\MCShop-API\node_modules\jsonwebtoken\verify.js:97:14)
at module.exports (U:\Coding\MCShop-API\node_modules\jsonwebtoken\verify.js:101:10)
at verifyJWTToken (U:\Coding\MCShop-API\src\crypto.ts:28:37)
at U:\Coding\MCShop-API\src\app.ts:39:45
at Layer.handle [as handle_request] (U:\Coding\MCShop-API\node_modules\express\lib\router\layer.js:95:5)
at trim_prefix (U:\Coding\MCShop-API\node_modules\express\lib\router\index.js:328:13)
at U:\Coding\MCShop-API\node_modules\express\lib\router\index.js:286:9
at Function.process_params (U:\Coding\MCShop-API\node_modules\express\lib\router\index.js:346:12)
at next (U:\Coding\MCShop-API\node_modules\express\lib\router\index.js:280:10)
"name": "JsonWebTokenError"
}
I have also attached the crypto.ts file that handles the JSON Web Tokens for my application.
import crypto from 'crypto';
import { readFileSync } from 'fs';
import { JwtPayload, sign, verify } from 'jsonwebtoken';
import { logger } from './app';
export function generateRSAKeyPair() {
const { privateKey, publicKey } = crypto.generateKeyPairSync('rsa', {
modulusLength: 512,
publicKeyEncoding: { type: 'pkcs1', format: 'pem' },
privateKeyEncoding: { type: 'pkcs1', format: 'pem' }
});
return { privateKey, publicKey };
}
export function generateJWTToken(admin: boolean, username: string) {
const key = readFileSync('private.key', { encoding: 'utf-8', flag: 'r' });
return sign({
admin,
username
}, key, { algorithm: 'RS256' });
}
export function verifyJWTToken(token: string) {
try {
const key = readFileSync('public.key', { encoding: 'utf-8', flag: 'r' });
const verifiedToken = verify(token, key, { algorithms: ['RS256'] }) as JwtPayload;
if (!verifiedToken) return false;
return verifiedToken
} catch (error) {
logger.fatal(error);
return false;
}
}
I have confirmed the following:
I suspect there might be an error in how I'm handling the keys or in the JWT library version.
Can someone help me identify the root cause of the "invalid signature" error and suggest potential solutions? Any insights or advice would be greatly appreciated.
I ran your code and it was fine. I had to change the modulusLength
, which is the key size in bits. For RS256 you would therefore set it to 256 * 8 = 2048
. You should be able to copy the 3 below files into a folder, then run these commands:
npm install
npm start
index.ts
import crypto from 'crypto';
import { readFileSync, writeFileSync } from 'fs';
import { JwtPayload, sign, verify } from 'jsonwebtoken';
export function generateRSAKeyPair() {
const { privateKey, publicKey } = crypto.generateKeyPairSync('rsa', {
modulusLength: 2048,
publicKeyEncoding: { type: 'pkcs1', format: 'pem' },
privateKeyEncoding: { type: 'pkcs1', format: 'pem' }
});
return { privateKey, publicKey };
}
export function generateJWTToken(admin: boolean, username: string) {
const key = readFileSync('private.key', { encoding: 'utf-8', flag: 'r' });
return sign({
admin,
username
}, key, { algorithm: 'RS256' });
}
export function verifyJWTToken(token: string) {
const key = readFileSync('public.key', { encoding: 'utf-8', flag: 'r' });
const verifiedToken = verify(token, key, { algorithms: ['RS256'] }) as JwtPayload;
if (!verifiedToken) return false;
return verifiedToken
}
const { privateKey, publicKey } = generateRSAKeyPair();
writeFileSync('./private.key', privateKey);
writeFileSync('./public.key', publicKey);
const token = generateJWTToken(true, 'john doe');
console.log(token);
const result = verifyJWTToken(token);
console.log(`Result is ${JSON.stringify(result)}`)
package.json
{
"name": "demo",
"version": "1.0.0",
"description": "",
"main": "index.ts",
"scripts": {
"start": "tsx ./index.ts"
},
"dependencies": {
"@types/node": "^20.11.0",
"jsonwebtoken": "^9.0.2",
"tsx": "^4.7.0",
"typescript": "^5.3.3"
}
}
tsconfig.json
{
"compilerOptions": {
"strict": true,
"target": "ES2022",
"lib": ["ES2022"],
"module":"ES2022",
"moduleResolution": "Node",
"allowSyntheticDefaultImports": true,
"sourceMap": false
},
"include": [
"*.ts"
],
"exclude": [
"node_modules"
]
}