79

I am new to Rails 4, and do not understand the use of secret_key_base under config/secrets.yml in Rails 4. Can you please explain this concept?

Also, when I am working in the production environment, I am prompted to set the secret_key with devise.rb, config.secret_key, and secret_key_base. However, I can generate a new secret using the rake secret command.

What is the difference between development and production environments?

How is it matching the newly generated secret_key when I add it with secret_key_base every time I generate?

How is it securing the application with other servers?

Andrey Deineko
  • 51,333
  • 10
  • 112
  • 145
Mani David
  • 1,382
  • 1
  • 14
  • 30
  • 5
    For readers using Ruby on Rails 5.2 or newer. `secret_key_base` is still used but stored in `config/credentials.yml.enc` instead. This file is encrypted. You can find more info about the new credential system [here](https://guides.rubyonrails.org/security.html#custom-credentials), or run `rails credentials:help`. – 3limin4t0r Jan 22 '20 at 14:58

2 Answers2

69

The secret_token.rb file's content includes a long randomized string which is used to verify the integrity of signed cookies (such as user sessions when people are signed into your web app).

Documentation says:

Use your existing secret_key_base from the secret_token.rb initializer to set the SECRET_KEY_BASE environment variable for whichever users run the Rails app in production mode. Alternately, you can simply copy the existing secret_key_base from the secret_token.rb initializer to secrets.yml under the production section, replacing <%= ENV["SECRET_KEY_BASE"] %>.

Since it is important file, and you can't put it to .gitignore, it is treated to be a good practice to use env variable to store secret_key_base value:

create .env or .powenv file and store it as:

export SECRET_TOKEN="9489b3eee4eccf317ed77407553e8adc97baca7c74dc7ee33cd93e4c8b69477eea66eaedeb18af0be2679887c7c69c0a28c0fded0a71ea472a8c4laalal19cb"

And then in config/initializers/secret_token.rb

YourAppName::Application.config.secret_key_base = if Rails.env.development? or Rails.env.test? # generate simple key for test and development environments
  ('a' * 30) # should be at least 30 chars long
else
  ENV['SECRET_TOKEN']
end

This article is (a bit old and) long but really full of useful info on the topic.


UPDATE 04.05.15

Starting from Rails 4.2 there is no longer secret_token.rb file. By new convention there is a config/secrets.yml file aimed to store application's secrets.

Have a read on how to upgrade an existing app to 4.2.x according to innovations.


Technically the purpose of secrect_key_base is to be the secret input for the application’s key_generator method (check Rails.application.key_generator).

The application’s key_generator, and thus secret_key_base, are used by three core features within the Rails framework:

  • Deriving keys for encrypted cookies which are accessible via cookies.encrypted.
  • Deriving the key for HMAC signed cookies which are accessible via cookies.signed.
  • Deriving keys for all of the application’s named message_verifier instances.

Check out more on each of the three in the article by @michaeljcoyne.

Andrey Deineko
  • 51,333
  • 10
  • 112
  • 145
  • Note if you are using something like Ansible or similar to deploy you can replace the entire secret.yml during production deployment and gitignore `config/secret.yml` if you prefer. – Kris Jul 19 '17 at 09:56
  • Actually, config/secrets.yml is introduced since Rails 4.1 – Fumisky Wells Sep 20 '17 at 02:04
  • All this means when you change `secret_key_base`, your users get logged out. At least. – x-yuri Jul 22 '19 at 12:45
28

secret_key_base is used to encrypt and sign session

in order to safely send session back and forth in cookies


In Rails 4,

  1. if your app is called Hello, and
  2. you set session['a'] = 'b',

your cookie will look something like this:

_Hello_session=BAh7B0kiD3%3D%3D--dc40a55cd52fe32bb3b84ae0608956dfb5824689

which translates into:

_Hello_session=<encrypted a=b>--<digital signature>

Cookies are set by server and kept client side, with browser resending set cookies to the server every time we request a page.

To prevent evil people from understanding a=b string, it's encrypted.
To prevent evil people from tampering cookies, digital signature is used.

In both cases secret_key_base value is used (to encrypt/decrypt a=b and to validate digital signature).

Community
  • 1
  • 1
Evgenia Karunus
  • 10,715
  • 5
  • 56
  • 70
  • 1. as I know session data is saved in the server and there is a session_id in cookie. eg. store user_id in a session, the only session_id can be seen by the browser while once login the server can know which user send the request by session_id. Here you say session['a'] = 'b' will encrypt the data inside cookie. I am not sure if you are confused between session and cookie. 2. how can a browser decrypt it without know the secret_key_base and get the information? – Damon Yuan Jul 19 '16 at 15:35
  • 3
    sorry, now I know rails is using cookie-based session, which means the session infomation is stored inside cookies. – Damon Yuan Jul 23 '16 at 08:03
  • yes that's correct, cookie-based sessions offer portability for sessions in distributed app servers and speed – hammady Oct 18 '17 at 06:42