Feature Request : Secured Template/Function node

Hello,
On all my projects I'm using a INIT trigger that run a "Reset" Function node to store in a global object config and function for all nodes.

let CLIENT = {
    UTIL : {},
    CONFIG : {
      azure : {  api_key : '0000'  }
    }
}
CLIENT.UTIL.getLanguage = () => { /* do stuff */ }
global.set("CLIENT", CLIENT);

It is very convenient because it let me store at the same place the configuration of the project. And I can improve it with a Link Node / JS Node to add content to the CLIENT for a dedicated feature. (Let say I have a OpenAI Tab, I can have a JS Node that add stuff to CLIENT.CONFIG.openai and called by main INIT trigger.

But there is a big limitation ! I put secrets into these Function Node. I'd love to have a kind of Secure Function that will store it's content into a crypted flow.

You will say ... use a Subflow with secure field and build the JSON into the node... Yes you are right ! But it require a lot on back and forth when adding a simple field. Worst for arrays (if I declare 3 GPT model that mead 3 fields or multiple subflow)

If you want a way to safely store credentials that the Function node can use, then you can add them as environment variables at the Group/Subflow/Flow/Global level (depending on how widely accessible you need them to be). The env vars can be stored as credentials (so they won't get exposed in the editor) and the Function node can use env.get('MY_TOKEN') to retrieve the value.

It wouldn't be practical to have a 'secure' function node in the way you describe as credential values never get returned to the editor - so you wouldn't be able to edit the content the next time you reloaded the editor.

Ah ah thnaks, understood, that would mean

  • putting secrets as environment variable in Settings > Environment > Credential
  • getting them as $env() in my function node to organize my global object

It's what I was thinking also with a Subflow node to do the job but the global UI is more flexible that the field UI of subflow.

You mention Group//Flow level for env variable there is an UI for that ? (I'm in v3) I don't see where it is.

As per the docs: Using environment variables : Node-RED

Flow/Group level environment variables
Since Node-RED 2.1

Environment variables can be set at the flow or group level. This is done in the appropriate tab in the edit dialog for the flow or group.

Group - env vars are scoped to within the group

Flow - env vars are scoped to within the flow tab

1 Like

Ah Yes, thanks ! I totally missed the Flow Env icon !

Hello, @knolleary can you clarify a usage in this documentation :
https://nodered.org/docs/creating-nodes/credentials#runtime-use-of-credentials

  1. In my Setting > Env I set 2 environment variable :
  • env-string-id with type String
  • env-string-secret with type Password

The goal is to have specific data related to the Node-RED and securly store the Password

  1. In my subflow I create fields
  • env-id with type String or Env
  • env secret with type String or Env

The goal is to have a generic node getting it's configuration like we discuss previously in this post.

  1. In my flow I create an instance of this Subflow passing the environment variable.
  2. In a Function node of the Subflow
    4.1 If I node.warn(env-id) I correctly get the value because it is a String
    4.2 If I node.warn(env-secret) I get "PWRD" because it is a secret

So how do I get the real secret ? In order to call a REST API ? For instance my OpenAI secret token, etc ... ?

May be it's not possible ? So why be able to store Env Credential ? Is it only for real OS process that would read System Env ?

What version of Node-RED are you using? There were a couple bugs around credential properties in Subflows in early 3.1.x releases.

I'm testing on 3.1.9

Can you share an example flow? From your description I'm not 100% sure on how you've got it configured.

Yes, may be I do not use correctly the feature. I think what I want to do is not possible by design.

So I set a key and a secret in global settings :

Then I pass to my subflow the setttings (I prefix all env variable with env- by convention)

Then a Function Node in the subflow use the variable:

Some notes:

  • It is a pseudo code and flow to explain. It build an AzureOpenAI client using "secrets"
  • Don't pay attention to getMessageproperty() it's a helper function to look for variable into msg in case a String is set in the subflow (because there is no msg.* field type)

Because the env-secret is a credential, according to the documentation, I can't read it in a function Node. So I can't use it to build a Config object. It is replaced by __PWRD__

My workaround is to use a String instead of a Credential. It works. But that means it won't be encrypted while stored in Node-RED files ?

I was hoping for some flow JSON i could easily import - but hopefully there's enough detail in the screenshots to figure it out.

Nothing in the runtime should ever 'see' __PWRD__ - that's the placeholder passed to the editor to mask the true value. Code in the runtime should have access to the actual value.

I assume that env-llm-key in the function node code is the name of the env var of the subflow labelled Key whose value you have set to the env var env-key?

@JpEncausse I've created a flow with the same arrangement you have:

  • Global env var called env-secret set as a credential type
  • Subflow with an env var called sf-secret configured to use the env value of env-secret
  • A function node insode the Subflow uses env.get('sf-secret')

When I run that with either 3.1.10 or 4.0, the function is getting the true value of the env-secret env var.

I wonder if the root issue here is the value of the credential has been set to __PWRD__ somewhere along the way - so the function node is getting its true value - its just been overwritten at some point.

Try editing your global env property and setting the credential value to what you expect it to be - deploy the changes and see if that fixes things.

Nick, did you reload the browser after setting the credentials? The credentials exist at that time, but no longer after the browser reloads because not loaded (normally).

Yes, I'm well aware of that. This isn't about the editor having access to the credentials - its whether the Function node can access them in the runtime.

I've checked setting credentials, editing credentials, adding extra credentials - all with browser reloads inbetween to ensure the editor doesn't have the 'true' value of existing credentials.

1 Like

Nothing in the runtime should ever 'see' __PWRD__ - that's the placeholder passed to the editor to mask the true value. Code in the runtime should have access to the actual value.

Thanks, that was my question. So I'm doing something wrong.

OMG you are right, it works on a simple test.

Humm ... I'll check what I'm missing.
Probably swithing fields might write the __PWRD__ like you said. I'll check that

Thanks, It works !!! Sorry for all the time lost.

I put the password/credential field, be carefull of the input string. Be carrefull not to edit again (to be sure of the value)