Hi, I would be wrong or there's a major security issue I found out with this module. You can decode my signed token and get all information from it without knowing my Secret: SkyFall
Implemented on: NodeJS v6.7, jsonwebtoken
Decode service: jwt.io
Token: eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyIkX18iOnsic3RyaWN0TW9kZSI6dHJ1ZSwic2VsZWN0ZWQiOnt9LCJnZXR0ZXJzIjp7fSwid2FzUG9wdWxhdGVkIjpmYWxzZSwiYWN0aXZlUGF0aHMiOnsicGF0aHMiOnsidXNlclBlcm1pc3Npb24iOiJpbml0IiwiX192IjoiaW5pdCIsIm5hbWUiOiJpbml0IiwiZW1haWwiOiJpbml0IiwidXNlcm5hbWUiOiJpbml0IiwiaGFzaCI6ImluaXQiLCJzYWx0IjoiaW5pdCIsImNyZWF0ZWRBdCI6ImluaXQiLCJ1cGRhdGVkQXQiOiJpbml0IiwiX2lkIjoiaW5pdCJ9LCJzdGF0ZXMiOnsiaWdub3JlIjp7fSwiZGVmYXVsdCI6e30sImluaXQiOnsiX192Ijp0cnVlLCJ1c2VyUGVybWlzc2lvbiI6dHJ1ZSwibmFtZSI6dHJ1ZSwiZW1haWwiOnRydWUsInVzZXJuYW1lIjp0cnVlLCJoYXNoIjp0cnVlLCJzYWx0Ijp0cnVlLCJjcmVhdGVkQXQiOnRydWUsInVwZGF0ZWRBdCI6dHJ1ZSwiX2lkIjp0cnVlfSwibW9kaWZ5Ijp7fSwicmVxdWlyZSI6e319LCJzdGF0ZU5hbWVzIjpbInJlcXVpcmUiLCJtb2RpZnkiLCJpbml0IiwiZGVmYXVsdCIsImlnbm9yZSJdfSwiZW1pdHRlciI6eyJkb21haW4iOm51bGwsIl9ldmVudHMiOnt9LCJfZXZlbnRzQ291bnQiOjAsIl9tYXhMaXN0ZW5lcnMiOjB9fSwiaXNOZXciOmZhbHNlLCJfZG9jIjp7InVzZXJQZXJtaXNzaW9uIjoidXNlciIsImZhY2Vib29rIjp7fSwiX192IjowLCJuYW1lIjoiU2FtIiwiZW1haWwiOiJXYWx0ZXJAcmVjcGljLmNvbSIsInVzZXJuYW1lIjoiU2FtIiwiaGFzaCI6ImU5YTM4ZTliYjBkYTFlOTgxNzU2YjE0MWI4YmM5MWUxNTI4NzYwMmU5YTZmODAzZWUwZWViMmI3MzgxMjkwODllODVlYmVkY2FkNGVhMjg4MWQ4ZWQ2N2E2NTk4MTQzZWU2YjFlOGI2Nzg2OWY4ZTJkMDIwMzgyZGFiMDFkMzczYWM4MDhmMzVlMDcyYTM2MTgzMGQ2YTgwZWIzMWQ0MzNlNjg0NGY0YmEwMWViOGFlOTRmM2ViOTQ1NWRhNGRmOTVkNmU1OGU0OTAxZDBiYTBlMWU2ZTUyMzY5MzYxMTU1MDA2NTYwYmMyMzc1NTQwZDUyYWRiODk4ZjViYWY3NTdlNzE0ZTcwOTBjMjA2MWY5MmJiNGM5MDY0ZGM5ZTMyOWZiMmU0MjY4MTY1ZTFkMWQyNjk1OGIzNDQzNzVjMjA1ODZiY2UxY2JmZjEzYTE2MjliYzNmOGMyZmNhYjUwODQ2NjA1ZTVjYjFjMzVhYWM4N2ZhNzkzZTUzMTIzYTMyNTZiNTcxMzhlZWU4ZDNhNzZmOWU5MjA5NmVkM2U2YjY1OGQwNDQ0YTgzNjM0ZjRjYjQ5YjMxNDYwMmM0MTg0ODg4MTMzMDJjYWFiZGJhYmNmZmZiMDkxNTI5ZGI3NGYwM2Y2ZDE5OTE0MmYxOWFmMzUxZTYxZjM1ZDVkMDVmNTZjNDU4NjcyY2E5ZTU3ODAxZDZhYmZkYTE2YTU0ZGI2MjkxNjI3ZGM1MGYzZWQyZDllYjYzOWE4N2ZhMDI5N2U2NjE4ZTdiZmRjODM2MTNjMTUwN2JmZWQ3NWExMWNkZmY2YjcyYjUwODc2MTZiMzg1Yzk3YTExNDUwNjI3NDVkODFkMDUxMDRiZDg2Y2EwMDE4M2NjMGIyNjQyYzAxN2JiN2VhMDJhZTBhNTJiYmY0ZWYxYWNjYTMxNzcwOGYzYTdhYmUxODU3MzQ3ZTBhMjRmZjAyZWJmZGVjNjdmMDJiMmNlMmY0MjU2ODYyNjgzOWZjZmE1ZDgxODBmM2E0MTUxMDVlNWFmODA5MmM3ZTc1ZjEzOGZhM2MzOGM3MmQwMjE5OTBkMWZlYmU2YjQ5MjQ4YmVlYTRiM2QwZDQxYjQ4YWY3MGM1MDAyMmZhMTg0NjY5ZDljMDhlOTNlNmNlYWExMzY4YTgzOGU4NmUyZWZhZTBiNzc4ZGE5NmNhMmM5OTc0MjQ1MjYwODlkNjgzNjM3ZGFmMTg4ZjIwN2EyMmNlYjc4MWQ3YTUxMTQ3ZjkyZTQ2MzViNGUxYjc1YzkyMzM2YzE0YjFhMDMxN2JjODNlYTc0ZTBhMmY4Y2NjMDIzMmVhNzBlZmVjZWE3NjNiMzIwZjZiNWY0MTFjMWM0OTczNDMiLCJzYWx0IjoiODM1YjQyZDQzNWZhNzU4ZGJhN2FiMGQwMzJlYzdjNWU4MjNiNzlmNTBlMWMxMzdkZWNlZWY5YzQxNjNmNDEzNCIsImNyZWF0ZWRBdCI6IjIwMTYtMTAtMTdUMDI6MTA6NTUuNTkxWiIsInVwZGF0ZWRBdCI6IjIwMTYtMTAtMTdUMDI6MTA6NTUuNTkxWiIsIl9pZCI6IjU4MDQzMzJmMTM0NmZiMWIyNDk4NTY3YiJ9LCJfcHJlcyI6eyIkX19vcmlnaW5hbF9zYXZlIjpbbnVsbCxudWxsLG51bGwsbnVsbF0sIiRfX29yaWdpbmFsX3ZhbGlkYXRlIjpbbnVsbF0sIiRfX29yaWdpbmFsX3JlbW92ZSI6W251bGxdfSwiX3Bvc3RzIjp7IiRfX29yaWdpbmFsX3NhdmUiOltdLCIkX19vcmlnaW5hbF92YWxpZGF0ZSI6W10sIiRfX29yaWdpbmFsX3JlbW92ZSI6W119LCJpYXQiOjE0NzgwNzg4MTcsImV4cCI6MTQ3ODA3OTExN30.JFSSHB5G0Jdxh_kWqoZuzilgIMa_9jllkI6A-V1Bdxo
How I sign it:
jwt.sign(user, process.env.JWT_SECRET, { expiresIn: parseInt(process.env.SESSION_TIMER) })
How I verify it:
jwt.verify (token, process.env.JWT_SECRET, function (err, decoded) {})
I even tried it with a private.key but you still can get the content of the token without private.key file.
Token: eyJhbGciOiJSUzUxMiIsInR5cCI6IkpXVCJ9.eyIkX18iOnsic3RyaWN0TW9kZSI6dHJ1ZSwic2VsZWN0ZWQiOnt9LCJnZXR0ZXJzIjp7fSwid2FzUG9wdWxhdGVkIjpmYWxzZSwiYWN0aXZlUGF0aHMiOnsicGF0aHMiOnsidXNlclBlcm1pc3Npb24iOiJpbml0IiwiX192IjoiaW5pdCIsIm5hbWUiOiJpbml0IiwiZW1haWwiOiJpbml0IiwidXNlcm5hbWUiOiJpbml0IiwiaGFzaCI6ImluaXQiLCJzYWx0IjoiaW5pdCIsImNyZWF0ZWRBdCI6ImluaXQiLCJ1cGRhdGVkQXQiOiJpbml0IiwiX2lkIjoiaW5pdCJ9LCJzdGF0ZXMiOnsiaWdub3JlIjp7fSwiZGVmYXVsdCI6e30sImluaXQiOnsiX192Ijp0cnVlLCJ1c2VyUGVybWlzc2lvbiI6dHJ1ZSwibmFtZSI6dHJ1ZSwiZW1haWwiOnRydWUsInVzZXJuYW1lIjp0cnVlLCJoYXNoIjp0cnVlLCJzYWx0Ijp0cnVlLCJjcmVhdGVkQXQiOnRydWUsInVwZGF0ZWRBdCI6dHJ1ZSwiX2lkIjp0cnVlfSwibW9kaWZ5Ijp7fSwicmVxdWlyZSI6e319LCJzdGF0ZU5hbWVzIjpbInJlcXVpcmUiLCJtb2RpZnkiLCJpbml0IiwiZGVmYXVsdCIsImlnbm9yZSJdfSwiZW1pdHRlciI6eyJkb21haW4iOm51bGwsIl9ldmVudHMiOnt9LCJfZXZlbnRzQ291bnQiOjAsIl9tYXhMaXN0ZW5lcnMiOjB9fSwiaXNOZXciOmZhbHNlLCJfZG9jIjp7InVzZXJQZXJtaXNzaW9uIjoidXNlciIsImZhY2Vib29rIjp7fSwiX192IjowLCJuYW1lIjoiU2FtIiwiZW1haWwiOiJXYWx0ZXJAcmVjcGljLmNvbSIsInVzZXJuYW1lIjoiU2FtIiwiaGFzaCI6ImU5YTM4ZTliYjBkYTFlOTgxNzU2YjE0MWI4YmM5MWUxNTI4NzYwMmU5YTZmODAzZWUwZWViMmI3MzgxMjkwODllODVlYmVkY2FkNGVhMjg4MWQ4ZWQ2N2E2NTk4MTQzZWU2YjFlOGI2Nzg2OWY4ZTJkMDIwMzgyZGFiMDFkMzczYWM4MDhmMzVlMDcyYTM2MTgzMGQ2YTgwZWIzMWQ0MzNlNjg0NGY0YmEwMWViOGFlOTRmM2ViOTQ1NWRhNGRmOTVkNmU1OGU0OTAxZDBiYTBlMWU2ZTUyMzY5MzYxMTU1MDA2NTYwYmMyMzc1NTQwZDUyYWRiODk4ZjViYWY3NTdlNzE0ZTcwOTBjMjA2MWY5MmJiNGM5MDY0ZGM5ZTMyOWZiMmU0MjY4MTY1ZTFkMWQyNjk1OGIzNDQzNzVjMjA1ODZiY2UxY2JmZjEzYTE2MjliYzNmOGMyZmNhYjUwODQ2NjA1ZTVjYjFjMzVhYWM4N2ZhNzkzZTUzMTIzYTMyNTZiNTcxMzhlZWU4ZDNhNzZmOWU5MjA5NmVkM2U2YjY1OGQwNDQ0YTgzNjM0ZjRjYjQ5YjMxNDYwMmM0MTg0ODg4MTMzMDJjYWFiZGJhYmNmZmZiMDkxNTI5ZGI3NGYwM2Y2ZDE5OTE0MmYxOWFmMzUxZTYxZjM1ZDVkMDVmNTZjNDU4NjcyY2E5ZTU3ODAxZDZhYmZkYTE2YTU0ZGI2MjkxNjI3ZGM1MGYzZWQyZDllYjYzOWE4N2ZhMDI5N2U2NjE4ZTdiZmRjODM2MTNjMTUwN2JmZWQ3NWExMWNkZmY2YjcyYjUwODc2MTZiMzg1Yzk3YTExNDUwNjI3NDVkODFkMDUxMDRiZDg2Y2EwMDE4M2NjMGIyNjQyYzAxN2JiN2VhMDJhZTBhNTJiYmY0ZWYxYWNjYTMxNzcwOGYzYTdhYmUxODU3MzQ3ZTBhMjRmZjAyZWJmZGVjNjdmMDJiMmNlMmY0MjU2ODYyNjgzOWZjZmE1ZDgxODBmM2E0MTUxMDVlNWFmODA5MmM3ZTc1ZjEzOGZhM2MzOGM3MmQwMjE5OTBkMWZlYmU2YjQ5MjQ4YmVlYTRiM2QwZDQxYjQ4YWY3MGM1MDAyMmZhMTg0NjY5ZDljMDhlOTNlNmNlYWExMzY4YTgzOGU4NmUyZWZhZTBiNzc4ZGE5NmNhMmM5OTc0MjQ1MjYwODlkNjgzNjM3ZGFmMTg4ZjIwN2EyMmNlYjc4MWQ3YTUxMTQ3ZjkyZTQ2MzViNGUxYjc1YzkyMzM2YzE0YjFhMDMxN2JjODNlYTc0ZTBhMmY4Y2NjMDIzMmVhNzBlZmVjZWE3NjNiMzIwZjZiNWY0MTFjMWM0OTczNDMiLCJzYWx0IjoiODM1YjQyZDQzNWZhNzU4ZGJhN2FiMGQwMzJlYzdjNWU4MjNiNzlmNTBlMWMxMzdkZWNlZWY5YzQxNjNmNDEzNCIsImNyZWF0ZWRBdCI6IjIwMTYtMTAtMTdUMDI6MTA6NTUuNTkxWiIsInVwZGF0ZWRBdCI6IjIwMTYtMTAtMTdUMDI6MTA6NTUuNTkxWiIsIl9pZCI6IjU4MDQzMzJmMTM0NmZiMWIyNDk4NTY3YiJ9LCJfcHJlcyI6eyIkX19vcmlnaW5hbF9zYXZlIjpbbnVsbCxudWxsLG51bGwsbnVsbF0sIiRfX29yaWdpbmFsX3ZhbGlkYXRlIjpbbnVsbF0sIiRfX29yaWdpbmFsX3JlbW92ZSI6W251bGxdfSwiX3Bvc3RzIjp7IiRfX29yaWdpbmFsX3NhdmUiOltdLCIkX19vcmlnaW5hbF92YWxpZGF0ZSI6W10sIiRfX29yaWdpbmFsX3JlbW92ZSI6W119LCJpYXQiOjE0NzgwNzkyNzgsImV4cCI6MTQ3ODA3OTU3OH0.I-SxubNLGPXYLtrxPSmxBPIbV_FE5WThwdthx0jXWW5OfADn-Ew27kgqCAOpeX41JWYbjA1CiJOU6pHJakt5toRrQF1g4XSU7nTOIhOaR2wn7cZ1cQZnjrxp-Vb_tr0BP1rAMHAuAWcAIZAj6kuietHuV_6FXDVKMB4sp9-vDEM
How I sign it:
jwt.sign(user, cert, { expiresIn: parseInt(process.env.SESSION_TIMER), algorithm: 'RS512' })
How I verify it:
jwt.verify (token, cert, function (err, decoded) {})
Please tell me I am wrong at some point, I really love the concept of JWT - so easy (and effective) to maintain sessions as well as tracking user data.
Thanks, Sam
JWT (at least by default, I think it is possible to encrypt the payload) does not encrypt the payload of your token, it just adds a signature so you can verify (with the secret) that the contents are not edited by some third party.
I was under the same impression as @nickschot. I only store permissions and the user's unique ID inside of the token, so even if it's decrypted the info is pretty much useless as they can't verify the signature without knowing the secret key it was originally signed with. I do know that some people choose to encrypt the payload, I've just never had the need to.
@nickschot , @mitchellporter: thank you for your message. I think that's the way jwt is.
@jfromaniello : I can see quite a lot traction from Google on this issue that developers want to have payload encrypted. Could you please consider to add this as a new feature?
And awesome job on jwt implementation by the way, super easy to use, nicely get the thing done. Thanks @jfromaniello and the team for your hard work!
@samsontr If you need it encrypted (not just signed and encoded), you want a JWE, JSON Web Encryption. It's not supported in this package but available in e.g. https://github.com/square/js-jose
Normally though, I'd say that's unnecessary…
@fiddur thank you for your suggestion. It is helpful.
Most helpful comment
JWT (at least by default, I think it is possible to encrypt the payload) does not encrypt the payload of your token, it just adds a signature so you can verify (with the secret) that the contents are not edited by some third party.