Secrets Management in iOS Applications

Secrets in iOS applications can be a bit of an issue, especially when you intend to make a project public. The problem here is that there is no good way to store and use secrets in a compiled application, so you end up with plain-text secrets littered about the codebase.

There are numerous solutions that exist but these seem to always end up with the conclusion of “whatever, just add it to the repo” or suggest building a full user authentication system where they log into your system via the application. The former is obviously an issue for an open sourced repo (less so for a private repo) and the latter adds a lot of overhead when sometimes you just want to use the Mapbox API.

In this article, I intend to tackle the issue of storing plain-text secrets in the repo.

Solving the secrets issue

For this problem, I found a method using encrypted JSON and Plist parsing to work quite well. Below, I explain how I set this up and how it works.

  • Store secrets in an ejson file somewhere in the repository. This is an encrypted JSON file using Shopify’s ejson library.
  • Add a Build Phase to the iOS app called Decrypt Secrets, the content of the script should simply be bin/secrets
  • Add a Plist file called Secrets.plist but leave it blank for now. Add it to Github in this state.
git add Secrets.plist
git commit -m 'Add blank Secrets.plist'
echo "Secrets.plist" >> .gitignore
git update-index --assume-unchanged Secrets.plist
  • Done!

How does it work?

The system works by decrypting the secrets.ejson file to a plist file that is compiled into the application. The Secrets class reads this plist file from the bundle and into a Swift dictionary. The entire application can now access the secrets using Secrets.secrets()['my_key'] as? String .

This means you no longer have to store unencrypted keys in the repo — a huge win for security.

On build, the secrets are decrypted and stored in plaintext in the app bundle— this doesn’t avoid that. But it does limit the exposure of secrets in the repo by not storing them in plaintext outside the app bundle.

The only caveat I have seen so far is that all users must now have ejson installed and place the private key that corresponds to your ejson file’s public key on their file system for the app to work, but this is not really a major issue if you have access to the developers of the app.

Infrastructure Engineer @ Shopify

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store