WHAT IS HAS_SECURE_PASSWORD?
has_secure_password is an ActiveRecord macro that works in conjunction with a gem called Bcrypt. To start, add the Bcrypt gem to your Gemfile and add has_secure_password to your user model. Finally, in order for these two to work, you must add a password_digest column in your users table which will store the cryptic password.
The following validations are added automatically when you add has_secure_password into your user model.
1. Password must be present on creation
2. Password length should be less than or equal to 72 bytes
3. Confirmation of password (using a password_confirmation attribute)
The first part ensures that a user account cannot be persisted to the database unless a password is entered in the signup form. The second part ensures that it doesn’t exceed a certain length. The third part adds a password_confirmation attribute which you can add to your form so that the user can enter their password in twice to confirm. Adding the line ‘validates_confirmation_of :password” ‘ will check the password confirmation. It it doesn’t match, it will add an error to the password attribute’s errors collection. Adding password_confirmation into your form is optional.
SO HOW DOES IT WORK EXACTLY?
Let’s say that a user is presented with your signup form to create their username and password. The user proceeds to enter the username and password. This information is sent with the HTTP request in your form to the create action in your UserController. Once the user is persisted into the database, a cryptic password value will appear in the password_digest column! But how does this happen!?
Let’s break it down layman style:
1. User enters in username and password to create an account
2. has_secure_password uses built-in validations for the user’s password ensuring that it’s not blank
3. If the password is valid, it will use the #password= method and pass your password in as an argument.
4. The #password= method will assign the password attribute in your user model to your newly entered, and unencrypted password.
5. It will then assign the password digest to an encrypted version of your password created by the Bcrypt gem.
6. Sometime before has_secure_password stores the encrypted password inside the password_digest, it passes the password to the Bcrypt gem which takes your unencrypted password as an argument along with a cost argument (will explain what that is in a moment)
7. It will “salt”, your password meaning it will add random strings of a fixed length to your password and then hash it
8. Finally, it will apply a default cost to your salted, hashed password which also means “hashing the hash”. If the cost is 10, it will hash your hash until the cost is met. I recommend reading more about it in the Bcrypt resource link I pasted below!
9. When bcrypt encrypts your password it will concatenate the cost, salt, and ciphered text into your password_digest column inside the users database.
HOW DOES BCRYPT AUTHENTICATE YOUR PASSWORD?
1. When a user logs in, has_secure_password will pass your unencrypted password to the authenticate method
2. Bcrypt will retrieve the stored salt and key from your ciphered text in the password_digest column and essentially encrypt the unencrypted password that was passed in using those keys.
3. If the newly encrypted password matches the stored encrypted password, then it is a match!
[rails/ at 375a4143cf5caeb6159b338be824903edfd62836 · rails/rails · GitHub](https://github.com/rails/rails/blob/375a4143cf5caeb6159b338be824903edfd62836/activemodel/lib/active_model/secure_password.rb#L113)
[bcrypt-ruby/ at master · codahale/bcrypt-ruby · GitHub](https://github.com/codahale/bcrypt-ruby/blob/master/lib/bcrypt/password.rb)
[Storing User Passwords Securely: hashing, salting, and Bcrypt](http://dustwell.com/how-to-handle-passwords-bcrypt.html)