I've created a private/public key pair using
openssl genrsa -out private.key 2048
openssl rsa -in private.key -pubout -out public.pem
When I try to sign/verify, it only works if I use the private key to both sign and verify.
If I use the public key to verify, I get the JsonWebTokenError: invalid algorithm error, no matter which key I used to sign.
And if I try to do it properly: sign with the public key and verify with the private key, I get the JsonWebTokenError: invalid signature error.
var key = fs.readFileSync('ssl/private.key');
var pub = fs.readFileSync('ssl/public.pem');
var json = {
jwtid: "sexy2puppy-" + new Date().getTime(),
issuer: 'Sexy',
audience: 'Puppy'
};
var s = jsonwebtoken.sign(json, key); // signing with private key
var p = jsonwebtoken.sign(json, pub); // signing with public key
console.log(jsonwebtoken.verify(s, key)); // works
console.log(jsonwebtoken.verify(s, pub)); // invalid algorithm
console.log(jsonwebtoken.verify(p, key)); // invalid signature
console.log(jsonwebtoken.verify(p, pub)); // invalid algorithm
Am I missing something here?
You need to specify an algorithm when signing. The #sign method defaults to HS256, so it's just treating your key as a passphrase for the HMAC.
The reason you were getting "Invalid Algorithm" is because #verify _does_ look at the key, decides it must be for one of the public key algorithms (ES or RS), but sees that doesn't match up with the token's HS256.
The correct way would be to sign with the _private key_, specifying an algorithm (such as RS256) and then verifying with the _public key_ (ideally also specifying the algorithm, but not necessary).
I understand your first part, about the default HS256 algorithm being the wrong one, that makes sense. I will try specifying RSA tomorrow at work for noth _#sign_ and _#verify_, and play with that.
However, the second part is a little confusing. Granted, I am not a network security expert, but if the private key is _private_, and the public key is open _publicly_, then when I sign with the _private key_, wouldn't anyone then be able to verify (decode) that message, since anyone can have the _public key_?
You are signing the message, not encrypting it. You are there only one that has the private key, and so it can be verified with the public key with confidence that the token has not been tampered with.
Given we are not encrypting, anyone can read the token whether they have keys or not.
Darn it. I finally understand now! Thanks!
I had the wrong impression of JWT. I was under the impression that the secret was used to encrypt and decrypt the header.
Now I understand that the header and the payload is just encoded, and that the signature itself is the part used to verify the sender.
My bad.
Most helpful comment
You are signing the message, not encrypting it. You are there only one that has the private key, and so it can be verified with the public key with confidence that the token has not been tampered with.
Given we are not encrypting, anyone can read the token whether they have keys or not.