Authentication
Published: 2023-02-24 02:06:28

While learning about user authentication in web development, I had some difficulty grasping all of the concepts, so I did a little research and I am writing about what I learned. Authentication, in the sense of web development, is the process of making sure our user is who they say they are before they are allowed to access the content.

So, if I'm building a website with users, and I want my users information to be secure, there' a few things I have to know. First, HTTP is a stateless protocol. It does not store the user data for me. Cookies allow additional information to be sent along with the request to the server. Cookies are usually used to save session info. Without them, a user would have to log in and be authenticated for every request. The session is a special cookie that Rails encrypts and signs. Rails manages all of the session data in a single cookie, serializing all of the key-value pairs into a single string. Whenever a key is set Rails updates the value of the session cookie to this big string. When cookies are set like this Rails signs them to prevent users from tampering with them. The Rails server has a key, configured in `config/credentials.yml.enc`. Rails has a method that returns a signature. The signature is an encrypted string. Given the same message and key, it will produce the same string. Also, without the key, it is practically impossible to know what would be returned for a given message. Meaning, signatures can't be forged. When a cookie is received, Rails will verify that the signatures match. Once the username and password have been authenticated, you receive a cookie. With it, you do not need to provide your username and password for every request. When a user logs in a cookie is set on the user's browser. That cookie writes their user id into the session's hash. 

The password should never be stored in the database as plain text. Instead, it should be stored as a hashed version, an encrypted string. There are many kinds of hashes, but they need to be complex enough to not be easily decrypted. Another common issue with hashes is that similar passwords can generate hashes with similar values. Sometimes these values "collide" with each other. One library that makes hashes is BCrypt. BCrypt is designed so that similar strings come out to be very different values, it is a cryptographic hash and is designed to be slow. it is intentionally computationally expensive. A salt is a random string prepended to the password before hashing it. It's stored in plain text next to the password, so it's not a secret. Rails makes this easier for us. There is a macro called `has_secure_password`. It is placed in the user model, and it gives access to methods used to authenticate the user. The macro grants access to two instance methods on the `user` model. These two methods enable `password` and `password_confirmation` to easily be added to a signup form. `has_secure_password` has a hook that checks if the password and password confirmation match unless the password confirmation is nil. If they match or the value is nil then the user is saved and the hashed version of the password is stored in the `password_digest`. It stores two values, the salt and the return value of BCrypt. `User.authenticate` is another method `has_secure_password` allows me to use. It takes the password the user inputs, puts it through the same encryption process, then checks that it matches the password_digest in the database.