Ruby on Rails, for many years now, has been an extremely popular and influential framework that allows a developer to quickly and cost-effectively build and deploy fully functioning backends. With that in mind, in nearly every complex web application the problem of user authentication will most definitely come into play. This guide will attempt to explain how you can quickly build secure authentication for your web application with Ruby on Rails.
Make sure the below items are installed on your machine before we begin.
Just like how we would normally create any Ruby on Rails project, we are going to run
rails new <name of project> --api. We are then going to need to change a few things in the gem file. Within the file "Gemfile" on line 17 there should be a commented line which reads
gem 'bcrypt', '~> 3.1.7' or something similar. Un-comment it out and add the line
gem 'jwt' below as well. It should then end up looking something like this.
Next, we are going to create our user model in which we are going to be using to authenticate. From our terminal, we are going to run
rails g scaffold User username:uniq password:digest. It is important to note that the digest at the end of
password:digest means that the user's password will not be stored as plain text within our database and adds a few extra goodies to our project. After our model has completed we are going to migrate our database using the command
rails db:migrate. After our migration we need to add the lines
validates :email, presence: true, uniqueness: true to the user.rb file within our models folder. This makes sure that when a new user is created that the username is unique within the database.
We are now going to create our Authenticate method from within our application controller file so any of our other controllers can access it when needed. Creating an empty method, our file should look like this.
The first thing we are going to check within our method is whether authorization headers were sent. To do that we can create a small if statement.
After we check whether the auth header was sent, we can then begin to decode our JWT token that should have been sent within the auth header. We should wrap the next few things within a begin rescue block of code which works similarly to a try-catch in other languages.
Within our begin/ rescue block, we should then decode our JWT token, find our payload, and get our user_id so we can then find our User within our database. To do this we will create a method named secret and token.
Our secret method will find a key within a secret key base which we can access like so.
We can then create our Token method which will access the second item within the auth_headers array.
Afterward, those two methods are created we can finish our Authorize method. All we need to do is get the user_id from our payload and then use that to find our authorized user.
For future application, we are going to add one last method to our application_controller which will be our create_token method.
The last thing we need within our Application controller class, for now, is to specify ours before action. All we are going to say here is that before anything else is attempted within our application controller we must authenticate first. to do that all we need to do is add
In the end, our application_controller.rb file should look like this.
Since our authentication controller is finished we will also want to make a change to our User controller. Specifically, we need to create a token whenever a new user is created. To do this we can use the create_token method we had made earlier within our create method like so.
For someone who is not creating a user for the first time, we need to create a login method. We will do this in a controller called AUthentication Controller. To create this controller rin
rails g controller authentication. A new file should then exist with your controller folder name authentication_controller.rb. Within this file, there should only be an empty class named AuthenticationController.
Within here we will then create our login method and make sure that it skips our authenticate method we had created earlier.
Within our method, we must first find our specific user using ruby's find_by method and then authenticate that user once found with our authenticate method we had created in our application_controller.
After we authenticate our user. We can then use the methods we had created earlier within our application controller to make a new JWT token for the user and also send all of the user data as JSON with the render method.
In the end, our authentication_controller.rb file should look like so.
The final step before we are finished with our fully functioning user authentication is to specify our login route. From within routs.rb which is located within the config controller, add
post 'login', to: 'authentication#login' which should send any /login request directly to our login method. The file should end up looking something like this.