Reputation: 983
I am having an issue with validating the JWT on the server side end of my node/express app. The token is being generated in Identity Server in an asp.net core app. The token that is generated is an RS256 token type, which means a private key and public key need to be generated on creation in the Identity Server. What that means for me -
On the client side (Angular) I'm passing in the Bearer token on all requests once signed in. I need to authenticate that token somehow. The way to do that with a RS256 token type is to make sure the public key matches. I'm using
const jwt2 = require('jwt-simple');
For my JWT validation.
The issue is the secret, here is the jwt-simple documentation jwt-simple link. If I make the third value in decode false it works, because it's ignoring the secret/cert that is required.
I'm getting this error -
Error: error:0906D06C:PEM routines:PEM_read_bio:no start line
I'm making this validation in the middleware so all endpoints will hit it. I saw this issue - SO Similar Issue and ran those same commands. I'm still getting the error because the token doesn't really have anything to do with the certs because I'm getting it from the Identity Server project. So I need to retrieve the cert public key from that project.
How would I be able to send that cert in the token or retrieve that valid cert somehow? Hopefully, this made some sense. Any help would be appreciated.
v1 - (using the self signed server.crt as the cert and getting this error)
Error: Signature verification failed
App.js
//This is for a self-signed certificate locally with no correlation to the token itself.
const options = {
key: fs.readFileSync('./key.pem', 'utf8'),
cert: fs.readFileSync('./server.crt', 'utf8')
};
app.use((req, res, next) => {
if(!req.headers.authorization){
return res.status(403).json({ error: 'No credentials sent!'});
} else {
let token = req.headers.authorization.split(' ')[1]
var decoded = jwt.decode(token, options.cert);
if(decoded){
let currentTime = new Date().getTime()/1000
if(decoded.exp <= currentTime){
return res.status(403).json({
error: 'Token has expired'
});
}
}
else if(!decoded){
return res.status(403).json({
error: 'invalid token'
});
}
}
next();
})
v2 - (using random text as the cert and getting this error)
Error: error:0906D06C:PEM routines:PEM_read_bio:no start line
App.js
app.use((req, res, next) => {
if(!req.headers.authorization){
return res.status(403).json({ error: 'No credentials sent!'});
} else {
let token = req.headers.authorization.split(' ')[1]
var secret = new Buffer('newsecret').toString('base64')
var decoded = jwt2.decode(token, secret);
if(decoded){
let currentTime = new Date().getTime()/1000
if(decoded.exp <= currentTime){
return res.status(403).json({
error: 'Token has expired'
});
}
}
else if(!decoded){
return res.status(403).json({
error: 'invalid token'
});
}
}
next();
})
So it seems I need a cert with the right signature that matches what was generated with the token.
JWT.io parsed token structure -
Header
{
"alg": "RS256",
"kid": "1231231231231231231",
"typ": "JWT",
"x5t": "si7bdXd6......HnxhO4Wi_s"
}
Do I do anything with x5t? Apologies for the long post. Thanks.
Upvotes: 5
Views: 3429
Reputation: 1171
I dig a bit and here is my investigation:
From node-jsonwebtoken docs, your secret must be valid private key.
secretOrPrivateKey is a string, buffer, or object containing either the secret for HMAC algorithms or the PEM encoded private key for RSA and ECDSA. In case of a private key with passphrase an object { key, passphrase } can be used (based on crypto documentation), in this case be sure you pass the algorithm option
Also, It will be better to provide the 'RS256' as third param in encode
and decode
function.
Checkout below sample code:
app.js
var jwt = require('jwt-simple');
var fs = require('fs')
var payload = { foo: 'bar' };
var secret = fs.readFileSync(__dirname + '/private.key');
var token = jwt.encode(payload, secret, 'RS256');
console.log(token);
var decoded = jwt.decode(token, secret, 'RS256');
console.log(decoded);
execution:
$ node app.js
eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiJ9.eyJmb28iOiJiYXIifQ.SKLxSFErngKdXEYQOP5faOZXHe2N_2EG1KjesPWKaZVvV6m5vTA_n77Y0K4x3ngCFQhv_CCwnAaK8BeBChgs5JUW9nMqnpTl73GkJLTzICC1Kl2hiH9724JuDyweAwoUsMntxFWMDhERhBPehHi10LZbH2BINmO-xxuLkMeemL0
{ foo: 'bar' }
sample private key:
-----BEGIN RSA PRIVATE KEY-----
MIICXQIBAAKBgQCGMBPo1UPwep2kHj1auLvyi6tJwwf/BS6rv3dDlwyXcQq4fLY4
ldNc+FOpYOKQF33ZltmNkmi2IQukNKZtzJtFyMRNARXIcttTARGL6NIfsYU80kmB
RCXjTc3rt088fmxij9HiXFQSpraKrt86ZQXnnkJyEGsQNuftm7yF7A3MOwIDAQAB
AoGAGGuxg+MkHSTDgbW7JsKN+eMvRhpHX0L7LmiG9PcNZJY/BDo2E3A46ieLWjz2
npCX57yLVTd69QJokva9/yeIblQpOIXw1U5PlID5mgjTTxJNzLPbXxjuWixZXKJ3
VHZXIAktbM36jdBj5gpxPmWgHa1+572pkx60QIXppKm+8AkCQQDHhQLpP3Z1Mq28
tnoL1NE9Ytxs0DHBkvWEFIbbPhhLPVMWLpCKuh92fNuTQrajMZtQOabaqz/ARI4u
Ty8uyM0lAkEArCyJaH2rRxFZuT7zrQKhuG9pDb/SDAplDEA1iREZmpWV4ClBN+7+
kMEypx7jz5kdlhN/y4oCS/BAaJgaoc3l3wJBAJBTMDLnfFn0yeZ7nTdXv/AGxmpU
A9oB42Wir5aCiXJLrwGZt2cSkdXVJcSVeqX8KVxUB9WgEOKU9MCc+QV/rZ0CQBzE
XDkPNjzrkzg2YnR3yhmM09quQCQu4G9JkyhRqRuA/sezXOhBkFsTTKlLqfiXtq/K
lkGlz3hsrfZL47dBNbUCQQDHUPfaAXQdbAns9O6s0wwXncaKo1r4QU4ZOQOc3mM0
e15fW/Ya22J2z9DUx8lNwMnoGzqBcVEPdHnFqbUJPZsw
-----END RSA PRIVATE KEY-----
Upvotes: 2