🚀Secure Rails Authentication: A Step-by-Step Guide to Sign Up, Log In, and Log Out

🚀Secure Rails Authentication: A Step-by-Step Guide to Sign Up, Log In, and Log Out

Table of Contents

 1. Introduction

       1.1. Setting Up a New Rails App

       1.2. Implementing Authentication

             a. Adding Authentication with Bcrypt

             b. Setting Up the User Model

       1.3. Signing Up

       1.4. Logging In

       1.5. Logging Out

       1.6. Conclusion

Introduction

Providing the security of web applications is paramount, and one of the binding aspects of it is authentication. It fosters the safe and secure sign-up, login, and logout of users.
In this article, we’ll dive deeper into the implementation of authentication in a Rails app, utilizing the built-in features and popular gems that are available.
From configuring authentication to managing user sessions, this article will cover everything you need to know to make your application secure and reliable.

We will begin by starting up a simple Rails application

Setting Up a New Rails App

To create a new Rails app, you should have Ruby and Rails installed on your machine. You can find how to install Ruby on your local machine using the Ruby docs. You can install Rails by running the following command:

gem install rails

Once Rails is installed, you can generate a new Rails app by running:

rails new rails_app

On a Windows OS, you would need to add bin/rails before your ruby prompt for the terminal to be able to recognize it. This applies to all your work on the terminal.

This will create a new Rails application with the name rails_app.

Next, navigate into the new app directory:

cd rails_app

To confirm that everything is set up correctly, you can run the Rails server, typing this on your terminal:

rails server

If the server starts without any errors, you should be able to access your new Rails app by visiting http://localhost:3000 in your web browser.
You should see a page like this on your browser

With the basic Rails app set up, we can now proceed to implement authentication features: user sign-up, login, and logout.

Implementing Authentication

Authentication is an important aspect of most web applications, allowing users to securely sign up, log in, and log out.

Adding Authentication with Bcrypt

Rails provides built-in support for secure password hashing using the bcrypt gem. We can add the gem to our Gemfile:

gem ‘bcrypt’, ‘~> 3.1.7’

After installing the gem, we can use the has_secure_password method in our User model. This method adds methods to set and authenticate against a BCrypt password.

Setting Up the User Model

The first thing we’d do is to create a User model to store user information. We can generate the model and its migration using the following command:

rails generate model User email:string password_digest:string

This will create a User model with email and password_digest columns. The password_digest column is used by Rails to store the hashed password instead of the plain-text password, ensuring better security.

Next, we’ll add validations to the User model to ensure that the email is unique and present, and the password meets certain requirements:

# app/models/user.rb
class User < ApplicationRecord
include ActiveModel::SecurePassword
has_secure_password
attr_accessor :password_digest

validates :email, presence: true

validates_format_of :email, with: /A[^@s]+@[^@s]+z/, message: “Must be a valid email address”
validates :password, presence: true
validates :password_confirmation, presence: true
end

The validates_format_of is a Ruby method that helps us set the format in which we want either our email address or password to be written.

The has_secure_password method adds methods to set and authenticate against a BCrypt password. It also requires the password_digest column to be present in the database.

Signing Up

We will need to create a route that our users can use to access the Signup page.
In our routes.rb file, we will have

get “sign_up”, to: “registration#new”
post “sign_up”, to: “registration#create”

The get request for the registration#new route will lead to the views we will create for our Signup page.
The post request for the registration#create route is a post request that we will use to send information our user will enter back to the database.

After this, we will create the controller to handle these actions.
Under our controllers folder, we will create a new file, registration_controller:

# app/controllers/registration_controller.rb
class RegistrationController < ApplicationController
def new
@user = User.new
end

def create
@user = User.new(user_params)

if @user.save
redirect_to root_path, notice: “Successfully created account!”

else
render :new
end
end

private
def user_params
params.require(:user).permit(:email, :password, :password_confirmation)
end
end

In our create method, we invoke the .save method in Ruby telling our application that if a new entry is made into the User model, it should save it to the database.

If you are wondering why we created the private method, you can read more on it here

Now, we will create our view. In your views folder, we will create a directory named registration and a file under it named new.html.erb

<!– app/views/registration/new.html.erb –>

<h1> Sign up Page </h1>

<%= form_with model: @user, local: true, data: { turbo: false }, url: sign_up_path do |form| %>

<% if @user.errors.any? %>
<div class=“alert alert-danger”>
<% @user.errors.full_messages.each do |message|%>
<div class=‘m-5’>
<%= message %> <% end %>
</div>
</div>
<% end %>
<div class=“mb-3”>
<%= form.label :email, Email Address %>
<%= form.text_field :email, class: form-control“, placeholder: myname@email.com %>
</div>
<div class=“mb-3”>
<%= form.label :password, Password %>
<%= form.password_field :password, class: form-control“, placeholder: strong password“%>
</div>

<div class=“mb-3”>
<%= form.submit Sign Up“, class: btn btn-primary %>
</div>
<% end %>

This view displays a form where users can enter their email and password.

Logging In

To allow users to log in, we’ll need a controller action and a view for the login form as well as a route to direct our users to it.
Just as we did in the registration route, in our routes.rb we will have:

get “log_in”, to: “sessions#new”
post “log_in”, to: “sessions#create”

The get request is to render our view for the log in page while our post request is to send information back to the database.

In our SessionsController, we will have:

# app/controllers/sessions_controller.rb
class SessionsController < ApplicationController

def new
end

def create
user = User.find_by(email: params[:email])
if user.present? && user.authenticate(params[:password])
session[:user_id] = user.id
redirect_to root_path, notice: “Successfully logged in”
else
flash[:alert] = ‘Invalid email or password’
render :new
end
end
end

The create method is telling Rails to check if the information it is receiving through the post request matches what is present in the database, and if so to redirect the user to the root page with a, ‘Successfully logged in’ notice.

In ournew.html.erb view:

<!– app/views/sessions/new.html.erb –>
<h1>Log In</h1>

<%= form_with url: sessions_path, local: true do |form| %>
<div>
<%= form.label :email %>
<%= form.text_field :email %>
</div>

<div>
<%= form.label :password %>
<%= form.password_field :password %>
</div>

<%= form.submit Log In %>
<% end %>

In the SessionsController#create action, we find the user by their email and authenticate them using the authenticate method provided by has_secure_password. If the authentication is successful, we store the user’s ID in the session and redirect them to the root path. Otherwise, we render the login form again with an error message.

Logging Out

To allow users to log out, in our homepage, we can add a link or button that leads the user to logout.
We do not need to create a view for this. We will just update our routes in our routes.rb file and update our sessions_controller.

In our routes.rb file, we will be making a delete request to the database that will correspond to a destroy method in our sessions_controller.

delete “logout”, to: “sessions#destroy”

In our sessions_controller, under our create method, we have the destroy methof.

# app/controllers/sessions_controller.rb
def destroy
session[:user_id] = nil
redirect_to root_path, notice: ‘Logged out successfully.’
end

This action simply removes the user_id from the session, effectively logging the user out and redirecting them to the root path.

Conclusion

In this article, we’ve covered the basics of implementing authentication in a Rails app, including signing up, logging in, and logging out. We’ve used built-in Rails features and the bcrypt gem to securely store and authenticate user passwords. This is just a beginner article and is a good starting point, but you may want to improve your knowledge by learning additional features like password reset functionality, account activation, and stronger password requirements for production applications.

I wrote an article on getting started with Ruby on Rails and building your first application! Check it out here

I hope this article has been good and helpful to you. I am still in the process of learning and becoming a better dev myself.
Let’s connect on LinkedIn.

Cover Image

Leave a Reply

Your email address will not be published. Required fields are marked *