I have an RSS aggregator app that helps me read newsletters and blogs from multiple sources without context switching. One of its features is to summarize articles using the Gemini API. I initially used my own API key for this, but I later decided to let users (if any, other than me) add their own key. Since we can’t store these keys directly in the database, encryption is necessary.
Why encrypt API keys?
Before we look at how to encrypt, let’s first understand why directly storing keys in the database is a bad idea.
Suppose keys are stored directly in the database. If the database ever gets compromised, then all the keys would be immediately accessible to attackers. Encryption ensures that even in the worst-case scenario, the keys remain protected.
How to encrypt?
Active record provides a built-in way to encrypt any model’s attributes. We will use that.
- First, generate a random key set
Run the command rails db:encryption:init
to generate keys
This will generate three keys.
active_record_encryption:
primary_key: EGY8WhulUOXixybod7ZWwMIL68R9o5kC
deterministic_key: aPA5XyALhf75NNnMzaspW7akTfZp0lPY
key_derivation_salt: xEY0dt6TZcAMg52K7O84wYzkjvbA62Hz
Add them to .env (or credentials storage if preferred).
- Now add the generated keys to config in application.rb
config.active_record.encryption.primary_key = ENV["ACTIVE_RECORD_ENCRYPTION_PRIMARY_KEY"]
config.active_record.encryption.deterministic_key = ENV["ACTIVE_RECORD_ENCRYPTION_DETERMINISTIC_KEY"]
config.active_record.encryption.key_derivation_salt = ENV["ACTIVE_RECORD_ENCRYPTION_KEY_DERIVATION_SALT"]
- Add api_key column
If the api_key
is missing in user
model, add it with migration.
class AddApiKeyToUsers < ActiveRecord::Migration[8.0]
def change
add_column :users, :api_key, :text
end
end
- Then declare encrypted attributes in model
Use deterministic: true
to ensure the key decrypts consistently. Without it, the result will differ on each decryption, making the application unable to use the correct API key for requests
class User < ApplicationRecord
encrypts :api_key, deterministic: true
end
- That’s it! Use encrypted key in your application
@api_key = Current.user.api_key
Rails will automatically encrypt the key when saving and decrypt it when accessed. This ensures the key is stored securely yet remains easily accessible.
Conclusion
Encrypting API keys is a simple yet powerful way to protect user data. With Rails’ built-in encryption, implementing this safeguard is straightforward and effective.