Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feature/fetch openaiKey via overrideConfig (vars) #2018

Merged
merged 4 commits into from
Mar 26, 2024

Conversation

niztal
Copy link
Contributor

@niztal niztal commented Mar 21, 2024

In order to support multi-tenancy and having the ability that a single chatFlow will support multiple customers with each customer potentially providing their own OpenAI key, we can implement the "customer_id" overrideConfig (as shown in the screenshot below). In this setup, the Flowise server will attempt to locate the corresponding credential in the Credentials table based on the provided customer_id. The customer_id supplied should match the name of the credential in the table.

For instance, if we use this embed code:

<script type="module">
        import Chatbot from "https://cdn.jsdelivr.net/npm/flowise-embed/dist/web.js"
        Chatbot.init({
            chatflowid: "e683f528-4f5f-4cf8-8f5b-25f7802c7de1",
            apiHost: "http://localhost:3000",
            chatflowConfig: {
                vars: {
                    customer_id: 'test'
                }
            }
        })
    </script>

and assuming I have an openai key credential already persisted by the name of "test" (for example in the below screenshot):

image

image

Then flowise server will decrypt this row's value and use this openai key.

@niztal
Copy link
Contributor Author

niztal commented Mar 21, 2024

@HenryHengZJ please review

@niztal
Copy link
Contributor Author

niztal commented Mar 22, 2024

@HenryHengZJ can you please review? I really need this to be part of upcoming release 🙏

@Jaredude
Copy link
Contributor

@niztal What's the result if a user passes in a customer_id value that's not in the credentials table?

Also, what prevents someone from changing the overrideconfig value and using someone else's customer_id, which would allow them to use someone else's API Key? Implemented as is, appears to me, would create a vulnerability into Flowise.

@HenryHengZJ
Copy link
Contributor

yeah I agree with @Jaredude, we can't tie the logic of retrieving credential to values set in vars. A better approach would be just allow users to pass in as part of overrideConfig:

<script type="module">
        import Chatbot from "https://cdn.jsdelivr.net/npm/flowise-embed/dist/web.js"
        Chatbot.init({
            chatflowid: "e683f528-4f5f-4cf8-8f5b-25f7802c7de1",
            apiHost: "http://localhost:3000",
            chatflowConfig: {
                openAIApiKey: "abc"
            }
        })
    </script>

@niztal
Copy link
Contributor Author

niztal commented Mar 23, 2024

yeah I agree with @Jaredude, we can't tie the logic of retrieving credential to values set in vars. A better approach would be just allow users to pass in as part of overrideConfig:

<script type="module">
        import Chatbot from "https://cdn.jsdelivr.net/npm/flowise-embed/dist/web.js"
        Chatbot.init({
            chatflowid: "e683f528-4f5f-4cf8-8f5b-25f7802c7de1",
            apiHost: "http://localhost:3000",
            chatflowConfig: {
                openAIApiKey: "abc"
            }
        })
    </script>

If user will provide the openai API key as plain text it won't be safe , rather than store it encrypted on flowise and fetch it by some unique id.

@HenryHengZJ

@niztal
Copy link
Contributor Author

niztal commented Mar 23, 2024

@niztal What's the result if a user passes in a customer_id value that's not in the credentials table?

Also, what prevents someone from changing the overrideconfig value and using someone else's customer_id, which would allow them to use someone else's API Key? Implemented as is, appears to me, would create a vulnerability into Flowise.

If user will provide non existing customer_id, the fallback would be to the provided API key over the node @HenryHengZJ

@HenryHengZJ
Copy link
Contributor

yeah I agree with @Jaredude, we can't tie the logic of retrieving credential to values set in vars. A better approach would be just allow users to pass in as part of overrideConfig:

<script type="module">
        import Chatbot from "https://cdn.jsdelivr.net/npm/flowise-embed/dist/web.js"
        Chatbot.init({
            chatflowid: "e683f528-4f5f-4cf8-8f5b-25f7802c7de1",
            apiHost: "http://localhost:3000",
            chatflowConfig: {
                openAIApiKey: "abc"
            }
        })
    </script>

If user will provide the openai API key as plain text it won't be safe , rather than store it encrypted on flowise and fetch it by some unique id.

@HenryHengZJ

in that case, are you dynamically generating new credential for every user? does that means if you have 1000 users, you will have 1000 credentials?

@niztal
Copy link
Contributor Author

niztal commented Mar 23, 2024

yeah I agree with @Jaredude, we can't tie the logic of retrieving credential to values set in vars. A better approach would be just allow users to pass in as part of overrideConfig:

<script type="module">
        import Chatbot from "https://cdn.jsdelivr.net/npm/flowise-embed/dist/web.js"
        Chatbot.init({
            chatflowid: "e683f528-4f5f-4cf8-8f5b-25f7802c7de1",
            apiHost: "http://localhost:3000",
            chatflowConfig: {
                openAIApiKey: "abc"
            }
        })
    </script>

If user will provide the openai API key as plain text it won't be safe , rather than store it encrypted on flowise and fetch it by some unique id.
@HenryHengZJ

in that case, are you dynamically generating new credential for every user? does that means if you have 1000 users, you will have 1000 credentials?

No,

I won't dynamically generate new credentials for every user.

Each customer has its own API key, and will get charge to openai by his usage.

Imagine one customer use 10 tokens a month and another one will use 10K tokens a month they will get charged accordingly.
If I'll have 1000 customers I will have 1000 credentials, yes. I don't see it as a problem, SQL will query that easily from the Credentials table.

Moreover I really think moving a variable named "openAiKey" will be vulnerable since it will be visible publicly to everyone, where "customer_id" is less explicit.

WDYT? @Jaredude @HenryHengZJ

@niztal
Copy link
Contributor Author

niztal commented Mar 25, 2024

yeah I agree with @Jaredude, we can't tie the logic of retrieving credential to values set in vars. A better approach would be just allow users to pass in as part of overrideConfig:

<script type="module">
        import Chatbot from "https://cdn.jsdelivr.net/npm/flowise-embed/dist/web.js"
        Chatbot.init({
            chatflowid: "e683f528-4f5f-4cf8-8f5b-25f7802c7de1",
            apiHost: "http://localhost:3000",
            chatflowConfig: {
                openAIApiKey: "abc"
            }
        })
    </script>

If user will provide the openai API key as plain text it won't be safe , rather than store it encrypted on flowise and fetch it by some unique id.
@HenryHengZJ

in that case, are you dynamically generating new credential for every user? does that means if you have 1000 users, you will have 1000 credentials?

No,

I won't dynamically generate new credentials for every user.

Each customer has its own API key, and will get charge to openai by his usage.

Imagine one customer use 10 tokens a month and another one will use 10K tokens a month they will get charged accordingly. If I'll have 1000 customers I will have 1000 credentials, yes. I don't see it as a problem, SQL will query that easily from the Credentials table.

Moreover I really think moving a variable named "openAiKey" will be vulnerable since it will be visible publicly to everyone, where "customer_id" is less explicit.

WDYT? @Jaredude @HenryHengZJ

Guys,

I feel there are few options here, please let me know what's your favorite:

  1. Moving the openAiKey as plain text - I think this is really bad since each user can view it via the browser's network and use it for his own purposes.
  2. Instead of openAiKey move credentialId which will represent the customer's persisted credentialId on the DB and change line to look for this as well from the nodeData.inputs?.credentialId From there it will work the same no other changes needed, the key is not exposed and each customer has its own credential's uuid
  3. Move the openAiKey encrypted and change line to call decrypt function if the param was taken from the nodeData.inputs?[paramName] - again same as first solution it may by danger since if flowise's user doesn't use encrypted keys, the key will need to move over the network as plain text.
  4. Use my original solution and move another implicit input (e.g. id) and use this to query the key over the db just by the credential's name and not by its id (very similar to the 2nd solution)

I prefer solutions 2/4 👍

@Jaredude @HenryHengZJ

Thanks

@HenryHengZJ
Copy link
Contributor

HenryHengZJ commented Mar 25, 2024

So if we go with solution 2, you'll have to implement your logic to retrieve the credential ID for the customer and pass in as:

<script type="module">
        import Chatbot from "https://cdn.jsdelivr.net/npm/flowise-embed/dist/web.js"
        Chatbot.init({
            chatflowid: "e683f528-4f5f-4cf8-8f5b-25f7802c7de1",
            apiHost: "http://localhost:3000",
            chatflowConfig: {
                "credentialId": {
                    "chatOpenAI_0": "abc123"
                }
            }
        })
</script>

Then we can implement the logic in ChatOpenAI.ts:

if (nodeData.inputs?.credentialId) {
    nodeData.credential = nodeData.inputs?.credentialId
}
const credentialData = await getCredentialData(nodeData.credential ?? '', options)
const openAIApiKey = getCredentialParam('openAIApiKey', credentialData, nodeData)

@niztal
Copy link
Contributor Author

niztal commented Mar 25, 2024

@HenryHengZJ it's works like a charm ✨

Please review, highly appreciated 🙏

@HenryHengZJ
Copy link
Contributor

Glad to hear!

@HenryHengZJ HenryHengZJ merged commit b177644 into FlowiseAI:main Mar 26, 2024
2 checks passed
@niztal niztal deleted the feature/openaikey_via_vars branch March 26, 2024 04:37
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants