Coder Social home page Coder Social logo

node-red-contrib-jwt's Introduction

node-red-contrib-jwt

Node-red node for sign and validate JWT tokens.

Functions

  • Sign msg.payload, msg.topic or msg.token using HS* or RS* algorithms.
  • Validate msg.payload, msg.topic, msg.token, req.headers.authorization or access_token var using HS* or RS* algorithms.

Roadmap

  • Handle certs better;
  • Validations;
  • Better UI.

Sample/Demo Flows

PEM Key File

This flow starts with injecting an RSA Private Key and Public Key each to a file (within node-red).

The Sign and Validate node will trigger a JWT claim to be signed using the Private key above (debugging the signed token), and then validating it with the matching Public key (debugging the validated JWT payload)

PEM Key File Example

Flow JSON:

[{"id":"5a455541.3fdcac","type":"tab","label":"PEM Key","disabled":false,"info":""},{"id":"254d3459.0f6a6c","type":"inject","z":"5a455541.3fdcac","name":"Sign and Validate","topic":"","payload":"","payloadType":"date","repeat":"","crontab":"","once":false,"onceDelay":0.1,"x":159,"y":213,"wires":[["b41b1ce9.4af46"]]},{"id":"952eeded.4e3b8","type":"jwt sign","z":"5a455541.3fdcac","name":"","alg":"RS512","exp":"3601","jwkurl":"","jwkkid":"rsa_priv_key","secret":"","key":"rsa_priv_key","signvar":"payload","storetoken":"payload","x":558,"y":212,"wires":[["923d5346.7095a","d6f89849.4d8f88"]]},{"id":"923d5346.7095a","type":"debug","z":"5a455541.3fdcac","name":"Debug Signed JWT","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"payload","x":780,"y":212,"wires":[]},{"id":"d6f89849.4d8f88","type":"jwt verify","z":"5a455541.3fdcac","name":"","alg":["RS512"],"jwkurl":"","secret":"","key":"rsa_pub_key","signvar":"payload","storetoken":"payload","x":554,"y":318,"wires":[["c4e176.85833e88"]]},{"id":"c4e176.85833e88","type":"debug","z":"5a455541.3fdcac","name":"Debug Validated JWT","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"payload","x":784,"y":318,"wires":[]},{"id":"b41b1ce9.4af46","type":"template","z":"5a455541.3fdcac","name":"Create Claims","field":"payload","fieldType":"msg","format":"handlebars","syntax":"mustache","template":"{\"sub\":\"user\",\"iss\":\"http://nodered.nulli.com:1880/oauth2\",\"tokenName\":\"id_token\",\"aud\":\"client\",\"azp\":\"client\",\"tokenType\":\"JWTToken\"}","output":"json","x":352,"y":213,"wires":[["952eeded.4e3b8"]]},{"id":"4bda0708.c98b08","type":"file","z":"5a455541.3fdcac","name":"","filename":"rsa_priv_key","appendNewline":false,"createDir":false,"overwriteFile":"true","x":707,"y":82,"wires":[]},{"id":"27b80fdd.cf946","type":"inject","z":"5a455541.3fdcac","name":"","topic":"Create Key Files","payload":"","payloadType":"str","repeat":"","crontab":"","once":false,"onceDelay":0.1,"x":166,"y":84,"wires":[["394036c2.6c15ea","48b5f522.c8aa7c"]]},{"id":"394036c2.6c15ea","type":"template","z":"5a455541.3fdcac","name":"RSA Private Key","field":"payload","fieldType":"msg","format":"handlebars","syntax":"mustache","template":"-----BEGIN RSA PRIVATE KEY-----\nMIIEpAIBAAKCAQEA2+d7uinqCDZYnZpyqCGnoeAR+aCWDC0YI7ZqKzH2RyjcHOpI\nIoswrPRZgF56y1x87a/QatPZmNmctEeNSNOM1qHfZSyxHCEyqENiNS3PEzUJ9RHK\nB7eDHKZGeQYhOmtXqm3zB8ORtVrngvDBsZT9A686p7Zo21ESOlXFZBieRVyimrEe\nJqcSwKq4gYG8GU7lc7r1fZCi81KL5K/6dxdMrmQeMYXgetH5SPIBFo4Mq47oJqiV\n48T87zCFHEzEikC+f1bbsNmOfryAwZtzTHQ7i/AU6kpOiNRMizC/cP7SNodc01Mk\nE1IXAv4fXTvEcmxTyRWPp2kiPR5oZ1R76B6v3wIDAQABAoIBAG1etQ/DFu3csbg4\n/7uVeX0uJ2KDNv15VB8285jmMXn03XzYHOZpWd07bmRFGUeZiVzh64OmN/wohyK2\nz5Mf/FUnjycP0kqOTFaZpPeUAACqiXhEz7mE0QXnwPciUFZw2tod8xiycP7E5o4e\nVgePdUNm3IJbW81wheNTk2gUQmt2Giwiu8ilcvPXyvNKBRLw+XM7UXINYtBk/7xM\ntcYd19mmjumUUXK4cw4qhoNE3l+GfCJ8S+FjCazLFCFnAe2CKX3CeJv7paoxenit\niQ6lQk1nhdN4+T5CnrTao1P9nBZiBqtvOICRDc+9QgMKHmmuPzPeYuqmGPd6F8s7\nMIQ4xvECgYEA8lxCg5sH4MUZbNFSn3fkP/iisiRzth4TXHv9OmdcRdTRSJrWXxND\nWbTb+Alj5vP4mBgxMTcycPS/qLSInQJaXjxEF4aQlBNLj4iZRvZENkseKrju+MyO\nJGOmcnkzfFiZLb/TLFMhBBpfVPItZci1kBE8/Mz6b9S1PmZnBWjdJfkCgYEA6Eex\nTtySIyLq/VQcuw+fgCI0lkZ0Ctg/nbs1YHbfMcyih60bWRsDX9KvexWy60nUQHNu\n/pc73rSW8ggIfTqx2UTHJTiNwBLm/XE2HxPnzcB6zf9CBhgqoQPxgBWfxtaiGCGR\nMyrsNxXt49LMUn2p6JNuLXtaKWweDfJbziLiGpcCgYEAkQFIPouENCRZKPU4lPbb\nlrbBSQpsPNtTxDLe+JGc8J77NJCHkEzrMAH41jdwEV+JLh7TV9npkRGullaloiMl\nRFqUdurpF99Phyo4Yu+3MjDRdMg/GpbwuK7yiG0hs9UimO+7fjqid1z8Csv3A34J\nu4/EyJAvirdeVV5ZZzAtmKkCgYEAmzIrmdFuIuPVtmVYvPN3UpmIIU/5gLVz6+OF\nimpiPlfH0Hcs6qBN5NxUOx0IaoTtuBJoetp5OhfXMueDJIjvA4gctxXOQCNhCr11\nt9YI70RHyRNf/cpv0R1dYoMQOj52F0F2ToXDRhr001+o/QTRXYAEAYeFel+uxQrF\npDlScQkCgYA7JewsTmXZyCfUytL9r+SxNjZLicmw2JALGBwavY5rZtSFKsmPr/zV\nDwjP9gtV6T/ObEshwDonI0tsDq6KOJB/8AI97uwcPa1c8x0jnfvRe9uoZ/qiKA+X\nqwqVkk/b6KowQo/XFMFa05batx2Xs41m5pQ/sSQPuR0FWHFVmKTF8g==\n-----END RSA PRIVATE KEY-----\n","output":"str","x":480,"y":83,"wires":[["4bda0708.c98b08"]]},{"id":"fd70bdee.e7ebd","type":"file","z":"5a455541.3fdcac","name":"","filename":"rsa_pub_key","appendNewline":false,"createDir":false,"overwriteFile":"true","x":706,"y":131,"wires":[]},{"id":"48b5f522.c8aa7c","type":"template","z":"5a455541.3fdcac","name":"RSA Public Key","field":"payload","fieldType":"msg","format":"handlebars","syntax":"mustache","template":"-----BEGIN PUBLIC KEY-----\nMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA2+d7uinqCDZYnZpyqCGn\noeAR+aCWDC0YI7ZqKzH2RyjcHOpIIoswrPRZgF56y1x87a/QatPZmNmctEeNSNOM\n1qHfZSyxHCEyqENiNS3PEzUJ9RHKB7eDHKZGeQYhOmtXqm3zB8ORtVrngvDBsZT9\nA686p7Zo21ESOlXFZBieRVyimrEeJqcSwKq4gYG8GU7lc7r1fZCi81KL5K/6dxdM\nrmQeMYXgetH5SPIBFo4Mq47oJqiV48T87zCFHEzEikC+f1bbsNmOfryAwZtzTHQ7\ni/AU6kpOiNRMizC/cP7SNodc01MkE1IXAv4fXTvEcmxTyRWPp2kiPR5oZ1R76B6v\n3wIDAQAB\n-----END PUBLIC KEY-----\n","output":"str","x":479,"y":132,"wires":[["fd70bdee.e7ebd"]]}]

JWK URL Keyset

The Sign and Validate node will trigger a JWT claim to be signed using an Private EC Key retrieved from a URL hosted by node-red (debugging the signed token), and then validating it with the matching Public EC key (debugging the validated JWT payload)

JWK URL Keyset Example

Flow JSON:

[{"id":"2bb941b5.7b5d9e","type":"tab","label":"Test JWT","disabled":false,"info":""},{"id":"920519b5.2b6e38","type":"inject","z":"2bb941b5.7b5d9e","name":"Sign and Validate","topic":"","payload":"","payloadType":"date","repeat":"","crontab":"","once":false,"onceDelay":0.1,"x":147.5,"y":214,"wires":[["60e22738.f40298"]]},{"id":"5138b19b.cd216","type":"jwt sign","z":"2bb941b5.7b5d9e","name":"","alg":"ES512","exp":"3601","jwkurl":"http://localhost:1880/priv_jwk","jwkkid":"nulli-ec-512","secret":"","key":"","signvar":"payload","storetoken":"payload","x":552.5,"y":213,"wires":[["6e7758b9.2b6f68","f900de63.1632b"]]},{"id":"6e7758b9.2b6f68","type":"debug","z":"2bb941b5.7b5d9e","name":"Debug Signed JWT","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"payload","x":774.5,"y":213,"wires":[]},{"id":"f900de63.1632b","type":"jwt verify","z":"2bb941b5.7b5d9e","name":"","alg":["ES512"],"jwkurl":"http://localhost:1880/pub_jwk","secret":"","key":"","signvar":"payload","storetoken":"payload","x":548.5,"y":319,"wires":[["f05412ad.d780a"]]},{"id":"f05412ad.d780a","type":"debug","z":"2bb941b5.7b5d9e","name":"Debug Validated JWT","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"payload","x":778.5,"y":319,"wires":[]},{"id":"4ba13e9e.f47c9","type":"template","z":"2bb941b5.7b5d9e","name":"Private JWK","field":"payload","fieldType":"msg","format":"handlebars","syntax":"mustache","template":"{\n  \"keys\": [\n    {\n      \"kty\": \"EC\",\n      \"d\": \"AXLoWyI1nApmP8lD1iFo3qjwBjJluXwNdYizbrcXpgUoX6F0gTtsOEQD9AxTqElgwHDfbs_IcwOSjfCh_4QeJnUM\",\n      \"use\": \"sig\",\n      \"crv\": \"P-521\",\n      \"kid\": \"nulli-ec-512\",\n      \"x\": \"AD0pM1Vkdw12HeM5AeY6PMuMbc66uG8oRiKV9hnm2x8U_dLgA7gRYNim4Y8_rixOeoHYlMzarRtDThLBS4CBlgrG\",\n      \"y\": \"ABuSEiwuSTIy02f1G2OnuSQN-9-s4KJxxXSqgMonKv3CPWaBVTJqfB4Viz9xUoY16d6ngJ2o66Kp2FUetTmxSptq\",\n      \"alg\": \"ES512\"\n    }\n  ]\n}","output":"json","x":339.5,"y":40,"wires":[["20446d4f.225862"]]},{"id":"20446d4f.225862","type":"http response","z":"2bb941b5.7b5d9e","name":"","statusCode":"200","headers":{},"x":535.5,"y":40,"wires":[]},{"id":"5790c71a.0ca028","type":"http in","z":"2bb941b5.7b5d9e","name":"","url":"/priv_jwk","method":"get","upload":false,"swaggerDoc":"","x":143.5,"y":41,"wires":[["4ba13e9e.f47c9"]]},{"id":"60e22738.f40298","type":"template","z":"2bb941b5.7b5d9e","name":"Create Claims","field":"payload","fieldType":"msg","format":"handlebars","syntax":"mustache","template":"{\"sub\":\"user\",\"iss\":\"http://nodered.nulli.com:1880/oauth2\",\"tokenName\":\"id_token\",\"aud\":\"client\",\"azp\":\"client\",\"tokenType\":\"JWTToken\"}","output":"json","x":346.5,"y":214,"wires":[["5138b19b.cd216"]]},{"id":"640d2eb5.4dec3","type":"template","z":"2bb941b5.7b5d9e","name":"Public JWK","field":"payload","fieldType":"msg","format":"handlebars","syntax":"mustache","template":"{\n  \"keys\": [\n    {\n      \"kty\": \"EC\",\n      \"use\": \"sig\",\n      \"crv\": \"P-521\",\n      \"kid\": \"nulli-ec-512\",\n      \"x\": \"AD0pM1Vkdw12HeM5AeY6PMuMbc66uG8oRiKV9hnm2x8U_dLgA7gRYNim4Y8_rixOeoHYlMzarRtDThLBS4CBlgrG\",\n      \"y\": \"ABuSEiwuSTIy02f1G2OnuSQN-9-s4KJxxXSqgMonKv3CPWaBVTJqfB4Viz9xUoY16d6ngJ2o66Kp2FUetTmxSptq\",\n      \"alg\": \"ES512\"\n    }\n  ]\n}","output":"json","x":342,"y":130,"wires":[["a03b5868.ec3528"]]},{"id":"a03b5868.ec3528","type":"http response","z":"2bb941b5.7b5d9e","name":"","statusCode":"200","headers":{},"x":538,"y":130,"wires":[]},{"id":"e53cbf9a.80f7f","type":"http in","z":"2bb941b5.7b5d9e","name":"","url":"/pub_jwk","method":"get","upload":false,"swaggerDoc":"","x":146,"y":131,"wires":[["640d2eb5.4dec3"]]}]

Useful sites:

node-red-contrib-jwt's People

Contributors

andyzickler avatar btsimonh avatar chameleonbr avatar rjaxin avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar

node-red-contrib-jwt's Issues

HTTP header based token error

Hello,

We are getting the following error when using bearer (header) based tokens:

{"message":"TypeError: Cannot read property 'header' of null","source":{"id":"816f695f.19d66","type":"jwt verify","name":"","count":1},"stack":"TypeError: Cannot read property 'header' of null\n at GetTokenHeader (/data/node_modules/node-red-contrib-jwt/jwt.js:166:21)\n at JwtVerify.<anonymous> (/data/node_modules/node-red-contrib-jwt/jwt.js:103:30)\n at JwtVerify.emit (events.js:189:13)\n at JwtVerify.Node.receive (/root/.nvm/versions/node/v10.15.3/lib/node_modules/node-red/node_modules/@node-red/runtime/lib/nodes/Node.js:237:14)\n at HTTPIn.Node.send (/root/.nvm/versions/node/v10.15.3/lib/node_modules/node-red/node_modules/@node-red/runtime/lib/nodes/Node.js:159:22)\n at HTTPIn.callback (/root/.nvm/versions/node/v10.15.3/lib/node_modules/node-red/node_modules/@node-red/nodes/core/io/21-httpin.js:199:26)\n at Layer.handle [as handle_request] (/root/.nvm/versions/node/v10.15.3/lib/node_modules/node-red/node_modules/express/lib/router/layer.js:95:5)\n at next (/root/.nvm/versions/node/v10.15.3/lib/node_modules/node-red/node_modules/express/lib/router/route.js:137:13)\n at metricsHandler (/root/.nvm/versions/no..."}

This happens when the authorization header have 'bearer' spelled all in lower case. From line 83 at jwt.js onwards:

        node.on('input', function (msg) {
            if (node.signvar === 'bearer') {
                if (msg.req !== undefined && msg.req.get('authorization') !== undefined) {
                    var authz = msg.req.get('authorization').split(' ');
                    if(authz.length == 2 && authz[0] === 'Bearer'){
                        msg.bearer = authz[1];
                   }
                } else if (msg.req.query.access_token !== undefined) {
                    msg.bearer = msg.req.query.access_token;
                } else if (msg.req.body !== undefined && msg.req.body.access_token !== undefined) {
                    msg.bearer = msg.req.body.access_token;
                }
}

I would suggest substituting that authz[0] === 'Bearer' by 'bearer' === authz[0].toLowerCase().

May i PR or something?

Environmental Variable/ Parameters for Client_Secret

Actually, I've the client_secret in my global variable. How can I use this global variable with the JWT_SIGN node? I'm using a pre-shared key and therefore my payload will have a client_secret which is then stored in a global variable. When I use the JWT_SIGN node, with HS256, it asks me to enter either a "secret" property on the node text input field or use an environmental variable NODE_RED_NODE_JWT_SECRET. Please help. Can I somehow use my global variable without having to enter the secret each time on the property of the node?

Originally posted by @ram1505 in #2 (comment)

Parameter `kid` appears in header even if not specified by the node

When generating a JWT with this node, the kid parameter is always included in the JOSE header even if that field is blank (it is set to the empty string). The presence of kid is causing some downstream APIs to refuse the token - which, admittedly, is probably their fault, but I'm hoping it's less friction to tidy up the token being produced.

                jwt.sign(msg[node.signvar],
                        node.secret,
                        {algorithm: node.alg, expiresIn: node.exp, keyid: node.jwkkid || null}, function (err, token) {

Flow doesn't continue when jwt is expired

I want to create a token authentication system, that returns 401 when token is expired. But this node throws TokenExpiredError, and the next node doesn't run, so I can't send http response. What can I do to make it work?

Unable to validate token

Screen Shot 2020-12-11 at 3 24 38 PM

I took your example and changed it a tiny bit.

I produce the token as you did, but just print the output so i can take then token and put it inside the injector.
When I inject the token to the validator, i always get TokenExpiredError: jwt expired even though the token is freshly created.

[{"id":"962b3fde.a6797","type":"inject","z":"5a455541.3fdcac","name":"","props":[{"p":"token","v":"eyJhbGciOiJSUzUxMiIsInR5cCI6IkpXVCIsImtpZCI6InJzYV9wcml2X2tleSJ9.eyJzdWIiOiJ1c2VyIiwiaXNzIjoiaHR0cDovL25vZGVyZWQubnVsbGkuY29tOjE4ODAvb2F1dGgyIiwidG9rZW5OYW1lIjoiaWRfdG9rZW4iLCJhdWQiOiJjbGllbnQiLCJhenAiOiJjbGllbnQiLCJ0b2tlblR5cGUiOiJKV1RUb2tlbiIsImlhdCI6MTYwNzcyOTAzMywiZXhwIjoxNjA3NzI5MDM2fQ.D044lZBYio6QeHqboCRYlJTgHrciAuuJozM1QtVHQiS_Kdbh-cQseMjkViD_alOj4orgDNLrRH7p1my5cbQhKgVEoibUgyGfKAVE7z5QWrvQdH3KMZbefNJl0c1mQ2QKAq1bEtYlZtRgWLJD97ydi4mpRPTla8jwutlPoJdDHnMW0lm-AxsH7BFijgWGXy5SA-luogMQB-YGMJkMIiU0mMZY2ELJclJVwgIDZrNB_qD7dkeT1SOqCl-cQOs3YC2eyViIgfvtkrRkgYkdk2WCtfFw1imfOP47RUWqIMtVpdNBZxt4QSo_ypYnnah3MxP8q8Y3-xU1BLSbHxGmJNormA","vt":"str"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"","x":390,"y":300,"wires":[["d6f89849.4d8f88"]]}]

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.