Skip to content


Subversion checkout URL

You can clone with
Download ZIP
Super easy password hashing and salting for ActiveRecord (Rails)
Branch: master

Fetching latest commit…

Cannot retrieve the latest commit at this time

Failed to load latest commit information.
lib Requiring at least Rails 3.0.4 (doesn't work in earlier versions beca…
spec Added helpful error to prevent validating against HashedString
.gitignore Generated gem skeleton
Gemfile Adjusted dependencies


Salt and Pepper

Provides automatic password hashing for ActiveRecord (>= 3.0.4) and a couple of methods for generating random strings, tokens, etc.

  • Mark columns for auto-hashing with a single line of code.
  • Automatic salting of hashes. No separate column is required for the salt.
  • Does not break validations on the hashed columns (only a small change is required).
  • Super easy hash verification.
  • Tested using RSpec 2

Digest::SHA256 is used for hashing and ActiveSupport::SecureRandom is used for generating random stuff.


Just add it to your Gemfile and run bundle install:

gem "salt-and-pepper"

Note: Rails 3.0.4 or higher is required.


To enable automatic hashing for a column, call hash_column in your model:

class User < ActiveRecord::Base
  hash_column :password

You can specify multiple columns in one line or in separate lines:

class User < ActiveRecord::Base
  hash_column :password, :security_token

  # or
  hash_column :password
  hash_column :security_token


You can pass the :length option to change the length of the stored hash.
Numbers between 96 and 192 are accepted, the default value is 128. Make sure the database column can store a string that long!

# set length for both columns
hash_column :password, :security_token, :length => 100

# or adjust them individually
hash_column :password, :length => 160
hash_column :secret, :length => 120

By default, blank (= empty or whitespace-only) strings will be converted to nil, and will not be hashed.
If you really want blank strings to be hashed, use the :hash_blank_strings option:

# Default behavior:
#                    nil => nil
#           empty string => nil
# whitespace-only string => nil

hash_column :password, :hash_blank_strings => true

# New behavior:
#                    nil => nil
#           empty string => 77c0a93ad8e5f42cf676...
# whitespace-only string => 1b8d091174299844b1a4...


Just compare the two values:

if @user.password == "secret"
  # password is valid

A full example:

# app/models/user.rb
class User < ActiveRecord::Base
  hash_column :password

# app/controllers/sessions_controller.rb
def create
  @user = User.find_by_username(params[:username])
  if @user.present? && @user.password == params[:password]
    # login user here
    redirect_to new_session_path, :alert => "Invalid username or password."

Validating hashed columns

Salt and Pepper provides the validate_[column]? method for deciding whether validations on the column should be performed.
Use it to prevent running your sophisticated length-checking algorithms on a 128-character hash :). Skipping validation of hashed values is safe because they were already checked at the time they were set.

class User < ActiveRecord::Base
  encrypt :password
  validates :password, :length => { :within => 6..100 }, :if => :validate_password?

Generating random stuff

Salt and Pepper has a couple of handy methods for generating random numbers, codes, tokens, etc:

SaltPepper.number(6)                                  # => 4     (identical to: 0..5)
SaltPepper.number(10..20)                             # => 11
SaltPepper.alpha_code                                 # => "SNPBJSDG"
SaltPepper.alpha_code(4)                              # => "FKNP"
SaltPepper.numeric_code                               # => "01570475"
SaltPepper.numeric_code(20)                           # => "70110124996934848762"
SaltPepper.code                                       # => "29Y3WSEC"     (alphanumeric)
SaltPepper.code(5)                                    # => "89U1F"
SaltPepper.code(10, 'a'..'z')                         # => "mqxeozlelw"
SaltPepper.code(15, (0..1).to_a + ('a'..'b').to_a)    # => "0ab1b0b1b01a0a1"
SaltPepper.token                                      # => "a0d5828f79e9e22dbc1f896e49f8183a"
SaltPepper.token(16)                                  # => "caa4a085edb19499"


Released under the MIT license.
Copyright © Máté Solymosi 2011

Something went wrong with that request. Please try again.