I am building a plugin with a client-side action that requires the user’s ETH wallet private key.
Obviously, this private key is extremely sensitive as it allows anyone with access, to withdraw all the funds from that given wallet.
The app builder will need to specify a private key in the plugin setup that will be used to approve transactions on the blockchain without needing the app user to approve them.
My idea was to suggest the app builder to save this private key in the database by creating a data type called “key” with a text field “private_key” and just save the private key here.
Then in the plugin setup, they would do a search for: keys: first item’s private_key.
My question is, what is the best practice to store this private key in the database and to be able to retrieve it via this search but make sure it can never be seen by anyone else other than the app builder/?
If they set the privacy rules to “Everyone Else” can find this in the searches does it mean that this can be retrieved in this search but then there is no other way to see it?
Maybe I have it completely wrong by storing it in the DB in the first place. My first instinct was to save it as a key in the plugin retrievable by context.keys but the private setting can only be used in server-side actions to my understanding?
We have been looking at this for quite awhile, here’s what we discovered:
The safest way is to NOT store it on your server, but instead store it to local storage, there are a few local storage plugins that will allow users to save and retrieve the private key value on their browser. That way, you have a non-custodial wallet; if your bubble server is ever compromised their keys are safe.
If you absolutely have to store it on a database, I would look at a KMS like strac.io - they will host the keys off your bubble server and encrypt them; they will issue a unique token identifier that can reference the key in your DB.
If you dont want to use a KMS and really want to store your keys on your DB, I would suggest creating a new data type like “wallet” with the privacy settings only visible to the wallet’s owner (add a User relational field); it cannot be searched for etc.; then when you ingest the wallet information you can encrypt it with an encrypt/decrypt plugin. That way when the data is at rest its obfuscated from any being read by a potential hacker- unless they get your encryption key (which will be in your encrypt/decrypt plugin settings). When you need to use the private key, you can just use a workflow step to decrypt then use that value in a subsequent step. However, it will be visible on your console logs.
There are also a lot of new plugins that enable typical web3 wallets that may be worth exploring. If you’re using ETH I’d look at a Metamask plugin; its a quick way to bring that wallet in for payments (and it’s non-custodial)
I’d recommend some sort of non-custodial solution; it is by far the safest.
Thank you very much for your answer here, this was very insightful I really appreciate it!
The reason I built this plugin was for a project I am building myself. Let me explain exactly the scenario I am working through, the local storage route seems ideal but I’m not sure it works for what I m trying to do. This is something like .env i guess?
I would like to use my private key for every user that comes onto the platform. I would essentially be performing all transactions for every user as I want it to be a gasless experience (building on polygon).
So I need to store my private key somewhere that can be retrieved by the plugin code when any user calls the element action. I could directly write it into the plugin code but I’m sure this is not secure.
Excuse my inexperience but, Is this possible at all through a client-side action does something like this need to be made as a server-side action to keep my private key hidden?
In this case you definitely do NOT want to store your private key on local storage. Then any moderately sophisticated user can access it and steal your funds. This needs to be server side.
I would use strac.io. Your private key will be tokenized, encrypted, and stored off your bubble server. Then only use it in backend workflows. This would make it difficult to get–unless they have access to your developer environment (use 2FA).
That being said, paying for all transactions with your own private key raises another attack vector: fraud. I’m not sure what your use case is, but take extra precautions in your order flows.
For instance, if you are fulfilling orders, attach a unique identifier to it that the user cannot read and use that to verify whether payment has been made or not made. Just something to think about.