Best way to store backend third-party API keys?

I want to build an interface to let me request signatures via the Dropbox Sign (HelloSign) API.

I’ll need to store the API credentials somewhere on the server. The same set of Dropbox Sign credentials will be used by all of the ERPNext users.

What’s the best method to securely allow System Managers to add/edit the API key?

You can set the fieldtype as a password field and so the data in the fields will be encrypted. to get the data in the field and use in your request, you can use a function similar to this:

def get_credentials():
    config = frappe.get_doc('Config Doctype')
   
    api_key = config.get_password(fieldname='api_key', raise_exception=False)
    api_secret = config.get_password(fieldname='api_secret', raise_exception=False)

    return api_key, api_secret

You can then pass the returned values to your requests.

I hope this helps.

Some credentials are also kept in site_config.json. db password, encryption key, mail config.

So you’re saying to create a new DocType called something like “HelloSign API” and then create fields for the API key and secret in that DocType?

Correct. This doctype will store the credentials. If you don’t want the data to be visible then make the fieldtype password. This will encrypt the data in the fields by displaying them as **************. the get_password function is able to fetch the encrypted data and pass it to your request function.

Hi @flexy2ky! Here are some remarks. They don’t really matter for the case at hand, and you may know these things already, but some concepts here are not clearly communicated. These precisions are important if you need to secure a data flow (or talk about it), like passwords or other data not to be divulged. Hope to having been useful for some reader at least.

Technically, hashing is a one-way function. (Like you can’t get back the meat once it’s hashed.)
If you can get back the original data from a hash, the hashing function is cryptographically defect (not working) or broken (like, with hash tables, listing all the hashes and turning back the data, these tables are so big that strong passwords need extremely big tables to recover the passwords, so big as to englobe the whole universe or so, you get the idea).

There are places where you use a hash instead of a password, but that’s different from what you try to achieve here.

What you mean is “encrypted”.

They are not stored as **************. Then they would all be the same and unrecoverable. They are just displayed as stars when typed. But they must somehow be transported to the backend database in a form which can be recovered in order to be used.
The important thing here is that they must somehow be protected in transit. This is non-trivial.
And I know that many are not exactly aware of how data transits between frontend and backend. There are ports, there is node, but it’s not explained in the doc, as far as I read it at least.

All this is from cryptography, a difficult and changing science in itself. Also stuff of films… Cheers!

@Peer Hi. Your remarks are noted and i clearly understand your points. However, if you review the post by the author, the request is to simply to hide the credentials not to encrypt it during transfer and my suggestion satisfies the use case requested. If you were thrown off by my use of the word hashed instead of encrypted

then i have edited it. If your second complaint is that i used the word storing instead of displaying here

I have also corrected that. Mind you however that whatever knowledge one has, no matter how basic or incomplete can serve as a base point for an eventually complete answer. Suggesting that concepts are not clearly communicated is breaching limits as even the author understood my initial response regardless of the “misuse” of concepts as you alluded in your post. All contributions whether right or wrong are voluntary and as such, no one should be called out, whether directly or indirectly, as you have done. There are tons of contributions in this forum that are either factually or structurally incorrect. But they serve as starting point for solutions because in their incorrect state, they trigger ideas for eventual solutions. If you have a different or better solution to the problem, provide your solution rather than calling out someone else’s purely voluntary contribution without providing an alternative which is exactly what you have done in this instance.

1 Like

Thank you for your remark, which I agree with mostly!
I’m generally appreciating your many helpful remarks in this forum, like anybody else’s too.
I didn’t want to call you out, but just give it a more personal touch, I’m sorry if I got this wrong.
Anyway, I tried to simply provide a better terminology, kind of the solution to a problem I saw, which is what you also asked for in your reply.
And I myself, indeed, sometimes (less with time and more reading and experimenting) get confused with the mix of versions and solutions in this tons of forum posts and also in docs. I still didn’t figure out many things in the framework, let alone erpnext, press, etc. Which is work in progress all the time anyway, since everything is worked on, which is why this forum exists, so we can interact and help each other see things we miss, if temporarily, so others find better info.
I’d suggest that we’re fundamentally on the same page, some occasional mishap notwithstanding.
Looking forward to reading more of you any time, and feel free to correct stuff I’m not getting right.