If I post a node with a *key*, is that key included in the post?

Hi Andrew, there are a rather confusing set of "answers" in this thread. Struggling to understand it myself now.

If I've kept things straight, the actual question was: how to avoid including some sensitive information (and API key) out of an exported flow?

My simple answer was to put the info in a context variable and use a change node to import it to the message that kicks off your API call. That is how I do it.

There are other options that others have used.

Then there was a separate discussion about making sure you have some data available when Node-RED (re)starts.

1 Like

With programming there's always lots of different ways to do something!

One way - API access via an http request, not a dedicated node. Save API key in a global context variable.
The first (ie leftmost) flow in your editor sets the context variable
image

[{"id":"6278fa1f309c5664","type":"tab","label":"The very first flow","disabled":false,"info":"","env":[]},{"id":"0e40150057777aa0","type":"inject","z":"6278fa1f309c5664","name":"Inject at startup","props":[{"p":"payload"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"","payload":"","payloadType":"str","x":200,"y":60,"wires":[["13e97f474aee0641"]]},{"id":"13e97f474aee0641","type":"change","z":"6278fa1f309c5664","name":"","rules":[{"t":"set","p":"myAPIkey","pt":"global","to":"1234567890abcdefghijklmnoq","tot":"str"}],"action":"","property":"","from":"","to":"","reg":false,"x":420,"y":60,"wires":[[]]}]

Here is an export of my complete Openweathermap flow.
You can see that I'm using an http request not a dedicated node.
You can import this flow and run it but because you don't have [my version of] the first flow with the real API key, OWM sends you an error message error 401.

[{"id":"800e3b2905246688","type":"tab","label":"OpenWeatherMap","disabled":false,"info":"","env":[]},{"id":"bd1120c9a023f3b5","type":"group","z":"800e3b2905246688","name":"Openweathermap","style":{"label":true,"fill":"#e3f3d3","fill-opacity":"0.57"},"nodes":["c342d046030f8660","28479ea02db80e49","df2c038951f8ea96","d599a16e7d6fead7"],"x":54,"y":59,"w":732,"h":82},{"id":"c342d046030f8660","type":"function","z":"800e3b2905246688","g":"bd1120c9a023f3b5","name":"Setup","func":"const owmid = global.get(\"myAPIkey\") || \"NoAPIkey\"\n\nmsg.url = \"https://api.openweathermap.org/data/3.0/onecall?\"\nmsg.url += \"lat=\" + msg.payload.lat + \"&lon=\" + msg.payload.long + \"&units=metric\"\nmsg.url += \"&appid=\" + owmid\nreturn msg;\n\n","outputs":1,"timeout":"","noerr":0,"initialize":"","finalize":"","libs":[],"x":290,"y":100,"wires":[["28479ea02db80e49"]]},{"id":"28479ea02db80e49","type":"http request","z":"800e3b2905246688","g":"bd1120c9a023f3b5","name":"Openweathermap","method":"GET","ret":"obj","paytoqs":"ignore","url":"","tls":"","persist":false,"proxy":"","insecureHTTPParser":false,"authType":"","senderr":false,"headers":[],"x":470,"y":100,"wires":[["d599a16e7d6fead7"]]},{"id":"df2c038951f8ea96","type":"inject","z":"800e3b2905246688","g":"bd1120c9a023f3b5","name":"","props":[{"p":"payload"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"","payload":"{\"location\": \"Peterborough\", \"lat\": 52.3611199, \"long\": -1.992723}","payloadType":"json","x":150,"y":100,"wires":[["c342d046030f8660"]]},{"id":"d599a16e7d6fead7","type":"debug","z":"800e3b2905246688","g":"bd1120c9a023f3b5","name":"debug 2577","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"false","statusVal":"","statusType":"auto","x":670,"y":100,"wires":[]}]

As long as I never post the real first flow, nobody can possibly see my API key.

Note that if I use a well designed dedicated node such as node-red-node-openweathermap instead, the API key that I set in the config is stored in flows_cred.json and it is never included with an export of the flow.

Either way, your API key is kept confidential.

1 Like

Thanks.

I lack the understanding on how to put theapi key value (sorry) I put the key in a change node, and inject that into the node.

And that is taken from context. Ok, I kind of get that.
But then - taking it to the stupid limits I do - I can still export the node with the credentials.

Should I start a new thread for this of just keep going?

Back to what you said:
(Ok, I'll stop here, I see I got anther reply so I'll read that and see what happens)

And, of course, if you have configured retained storage for your context variables (e.g. file storage), you wouldn't need to worry about doing this at startup, just make it a retained variable for your own use.

Good point.
Note that you have quoted me before I changed a typo.

1 Like

Ok, thanks.

That kinda makes sense.

(Sorry brain fog just now)

So I have a dedicated flow where I set any such things.
I guess it confused me with the global declaration - me being anal - when it is more a flow.
But yet, I see why that is done.

(Dunno if you could *cheat) and set/inject the credentials on one flow then link to that flow (if only used on one flow) and have the change node on that flow and set it to flow rather than global.

Though I digress, that is me being silly in how I think.

I'll now check what Julian said in his most recent post.

jbudd's more complete example shows you the way for both things. Note that he has 2 flows. 1 does the actual work and only references the variable with the sensitive data so it can be safely exported.

The other sets the variable and so could be included in an export if you do need to do that.

So great all round. :slight_smile:

I use a global context variable because it is set on one editor tab and used on a different tab.

When I export the entire flow that uses the variable, as I did above, you can see the name of the variable but not it's value.

Hmm On another machine I have multiple weather APIs all together on one editor tab. I can access them with links, passing in msg.latitude, msg.longitude and msg.apikey. In that case the API key[s] are set on the flow that links to this one. They could be flow context variables on that flow.

Yeah, ok, I didn't read the first flow quite as well as I should.

I took it as you entered the key in the inject node and sent it to the change node.
MY MISTAKE - sorry.

So, if I did it that way, I could link the inject to change node and put the change node on the other flow so the key would be flow and not global.
Again, I am not trying to be petty, just the brain fog is sort of corrupting things and I am discussing it to help clear the fog.

As @GogoVega and myself have noted it is probably best to use environment variable credentials, as they are kept securely, these can be set by flow or group or globally in the setting.js.


They are held in the flows_cred.json, in the .node-red directory and are encrypted
You can access them in a change node, function node or template node.

example

[{"id":"613df62afc8a16bf","type":"tab","label":"testing","disabled":false,"info":"","env":[{"name":"my_api_key","type":"cred"}]},{"id":"9a35d547d76baf73","type":"inject","z":"613df62afc8a16bf","name":"","props":[{"p":"payload"},{"p":"topic","vt":"str"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"","payload":"","payloadType":"date","x":100,"y":80,"wires":[["f88999acad5cab67","1d928297cda93681","d26902a1a5af9bb6"]]},{"id":"56631130f4851387","type":"debug","z":"613df62afc8a16bf","name":"debug 2575","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"payload","targetType":"msg","statusVal":"","statusType":"auto","x":450,"y":60,"wires":[]},{"id":"1d928297cda93681","type":"function","z":"613df62afc8a16bf","name":"function 159","func":"msg.payload = env.get(\"my_api_key\")\nreturn msg;","outputs":1,"timeout":0,"noerr":0,"initialize":"","finalize":"","libs":[],"x":290,"y":120,"wires":[["56631130f4851387"]]},{"id":"f88999acad5cab67","type":"change","z":"613df62afc8a16bf","name":"","rules":[{"t":"set","p":"payload","pt":"msg","to":"my_api_key","tot":"env"}],"action":"","property":"","from":"","to":"","reg":false,"x":280,"y":60,"wires":[["56631130f4851387"]]},{"id":"d26902a1a5af9bb6","type":"template","z":"613df62afc8a16bf","name":"","field":"payload","fieldType":"msg","format":"handlebars","syntax":"mustache","template":"{{env.my_api_key}}","output":"str","x":320,"y":180,"wires":[["56631130f4851387"]]}]

Enter your key in the flow properties environment var tab shown in first image.

I have shared the flow and the my_api_key was set to above image value, you can see in the flow i posted that they have not been shared.

1 Like

I'll have to look more into passing the key via the message.

Alas I have a problem that I get weather for a few places so I am going to have to think about that a bit more.

Thanks.

That way does look nicer.

(No offense to @TotallyInformation or @jbudd )

I'm changing horses a bit just now but this way seems to feel nicer to me.

I'll sit down and see if I can understand this way.

Small reminder :grin:

I'm now kinda more confused than before.

I am sure the node I am using is openweathermap but when I look at the posts/flows just now, the node when opened looks way different to the one I have.

Oh, ooops.
So the newer flows are not using that node, but a http request node.
But with the messages sent into it, it gets what I would get from the openweathermap node.

Yes?

And, despite a few attempts, I don't know what the correct address is I should be using, as every time I try I get an error back to me. :frowning:

This is what I have in my notes:

OpenWeatherMap's OneCall API One Call API 3.0 - OpenWeatherMap - free tier gives 1000 calls per day. Icons: https://flows.nodered.org/flow/d7af9f5d6f6923324466c58ea4f0655f

Thanks.

It wasn't your flow that threw me, but with the http request ones, nothing works.

I use the actual node. It works.

If I use the http request node and weak where I get the weather I get errors like crazy.

I'm trying to go with that as it seems the easier way to go. (He said now kind of regretting it)

This s to what I changed the function node just before the node:

const owmid = global.get("myAPIkey") || "NoAPIkey"

msg.url = "https://api.openweathermap.org/data/"
msg.url += "city=" + msg.payload.city + "&country=" + msg.payload.country + "&units=metric"
msg.url += "&appid=" + owmid
return msg;

note the change to the URL.

msg.url = "https://api.openweathermap.org/data/3.0/onecall?" is the old/original one.

If I use as was I get:

{"cod":401,"message":"Please note that using One Call 3.0 requires a separate subscription to the One Call by Call plan. Learn more here https://openweathermap.org/price. If you have a valid subscription to the One Call by Call plan, but still receive this error, then please see https://openweathermap.org/faq#error401 for more info."}

Which says I have not given a valid key - or it is there.
I stuck a debug node and it is there.

I don't know what kind of account @marcus-j-davies has.

I tried to make it for my account - guessing.
No luck.

I'll have to try and find this out.

Openweathermap have upgraded to version 3 of their api, so you would need to sign up for a new subscription to get api-key to use V3.
The update openweathermap node now use V3 also, that to will require a new subscription.

As noted in the error message.

I don't actually use any weather API.
It's either really cold, or really hot in Bristol, UK - the thing I do, is reverse the forcast - it usually works :joy:

2 Likes

Yeah, I get what you mean. Forecasting is not much better than sticking your arm out the window.

But this little quest has sent me down a confusing rabbit hole with the http request node.

Sorry, I never meant to send you down a rabbit hole, it just happens that I use http request rather than the dedicated openweathermap node. For no good reason that I'm aware of.

I think I assumed that you do too because with the dedicated note there is no change of revealing your API key when you export the flow, and I thought you had said that happened.

Well it carries a lower risk of catching a bite from an alligator, drop bear or huntsman, or getting skin cancer! (my experience of Australia was short but scary)

1 Like