Tuesday, December 10, 2013

How I Hide Important Credentials In My Rails Apps

I have been mentoring ruby on rails web development students for over a year now, and every quarter I end up explaining to them how I hide important passwords or credentials from showing up publicly on Github.  The most common way of hiding this information is through the use of environment variables.  Everybody seems to have their own unique way of handling this situation.  One popular option is to use the gem Figaro.  One advantage to using Figaro and Heroku together is that you can use their handy rake task to set all of the environment variables on your Heroku server.  Although using the gem is handy, I still prefer rolling my own solution.  Why use a gem when you can easily write your own solution and learn something along the way?

The first thing we need to do is create a file that will assign all of our environment variables locally.  We are going to create this in the config folder, and name it env_vars.rb.


Since this file will contain confidential information that we do not want visible on Github, we will want to add it to our .gitignore file.  Do this by creating or opening up your .gitignore file, and add the following line to tell git to not track our file.


Now we will assign each of our environment vars inside the env_vars.rb file.  In my case, I will add a couple keys to access Stripe.  In ruby we assign environment variables as follows:

ENV["STRIPE_SECRET_KEY"] = 'sk_test_Xxx0xxxXxXXxXxxXXXxxX0X0'
ENV["STRIPE_PUBLIC_KEY"] = 'pk_test_Xxx0xxxXxXXxXxxXXXxxX0X0'

Now we need to tell our Rails app to load these environment variables when the server is started locally in our development environment.  To do this we will modify our environment.rb file as follows:

# Load the rails application
require File.expand_path('../application', __FILE__)

#load env_vars file for development
env_vars = File.join(Rails.root, '/config/env_vars.rb')
load(env_vars) if File.exists?(env_vars)

# Initialize the rails application

The lines that load and initialize your app are already included in your enviroment.rb file by default. It is important that you add our new lines of code after the rails app is loaded, but before the app initializes.  Lets break down what we are doing here.

env_vars = File.join(Rails.root, '/config/env_vars.rb')

In this line we are creating a variable named env_vars that equals the path that leads to the env_vars.rb file that we created.

load(env_vars) if File.exists?(env_vars)

In this line, we are going to load the env_vars.rb file if that file exists.  It is important to have this conditional statement so that the app will still load if the file is not present.

Everything is now set up to work locally, but how do we get this to work on Heroku?  Start by running the following command from terminal:

heroku config:set STRIPE_SECRET_KEY=sk_test_Xxx0xxxXxXXxXxxXXXxxX0X0 STRIPE_PUBLIC_KEY=pk_test_Xxx0xxxXxXXxXxxXXXxxX0X0

Notice that you can assign multiple variables at the same time by just adding a space in between them as I did above.

If you are not using Heroku for production, then you can just place an env_vars.rb file in the same location on the production server that has all of your credentials.

That's it.  We can run the same or different values for our environment variables in development and on Heroku.  Just don't forget to assign your ENV's on Heroku or you will be thrown an error when your app tries to access the unassigned environment variable.  Fell free to drop me a comment if you have any suggestion on how to improve this, or if you have a better solution.