How to store credentials securely? (Drafts 5 Credential equivalent?)

How can I securely store credentials? (or API keys and shared secrets)

The Credential object in Drafts 5 works great for that.

Can we do something similar in Scriptable? (now or in the future?)

This is something that’s pretty high on my todo list but I haven’t found the right approach yet. For now, I’ve been thinking of a two step solution.

  1. A key/value pair can be securely stored in the keychain from the apps settings. So in settings there would be an entry named “Keychain”. When opened, users will be presented with a list of keys they have added to their keychain. From here, they can add and remove keys.
  2. Add a Keychain API which can read from the keychain but not write to it. That way scripts cannot modify the keychain but they can read existing keys.

I think that’s a simple and secure solution. Adding credentials from the script can quickly get complicated because I think that in many cause you would only want to do this in case the credentials doesn’t already exist.

I still haven’t ruled out a solution that only involves a Keychain API, i.e. support for reading AND writing to the keychain but I fear it gets too complicated.

I’d love to know what you think about the approach described above :blush:

4 Likes

For storing the RTM API key and shared secret this “simple” solution would work.

However, I would also like to store a token (which I currently store in iCloud) programmatically, so I would like to write to the keychain as well.

I like what you did in the beta for 1.0.1 :wink:

PS: there’s a typo in the documentation of this new feature (“cna” should be “can”)

1 Like

@simonbs Found the Scriptable app, pretty slick! I’m trying to pull some data from the DarkSky API, and would like to store the key securely so it is not in the code. I found the Keychain docs, but while option (1) seems easier for this, I couldn’t find it in the settings. Was it thrown out as an option?

For option (2), do you just write a one-off script to store the key? Is there a format for keys, e.g. scriptname-keyname, or anything in particular?

Thank you

That’s what I ended up doing.

Additionally I added this script to .gitignore to make sure that Working Copy won’t push it to GitHub.

1 Like

I’ve been considering adding an API that will prompt the user to enter a value if the key does not already exist in the keychain but haven’t gotten around to it (yet). For now, I have written a JavaScript function that does just that and I use it across some of my scripts. That way, I don’t store the key in the script and I can easily share my script.

I haven’t implemented option 1. I haven’t ruled it out yet either that I’ll introduce it in a future update but currently there’s other new features with a higher priority :blush:

4 Likes

Great, thank you. I haven’t figured out how to tie in Working Copy yet, but I’ll keep that in mind.

Could you add a “get all keys” to the keychain? Does that create a major security problem somehow? I just know eventually I’ll store something in there and forget what I called it and it’ll bother me that there’s something in the keychain I can’t get to.

That would be great!

In the mean time you can save the keys to an iCloud or local file and read that file later on to remember the keys again.

How do you store something in the KeyChain?

If it’s via a script, can’t you use that script to look up the keys?

That’s a good idea and would be easy to transition to something official if it comes.

I use

const kc_s1 = "lilf_s1";
var lilf_s1 = "";
if (Keychain.contains(kc_s1)) {
    lilf_s1 = Keychain.get(kc_s1);
} else {
    // Alerts aren't supported in widgets, so you need to run this script manually to set this up
    alert = new Alert();
    alert.addSecureTextField("Enter secret", "");
    await alert.presentAlert();
    lilf_s1 = alert.textFieldValue(0);
    Keychain.set(kc_s1, lilf_s1);
}