DEV Community

samanthamarberger
samanthamarberger

Posted on

Understanding Authorization vs. Authentication in Rails

We all know the importance of security in our web applications. We need to protect our data and customers from potential data theft or other types of cybercrime. However, there are different pieces required to make a secure application. Things like proper session management or the use of cookies can be useful, but today I am going to be writing about Authorization and Authentication. When I first learned about these I struggled remembering which was which and how to implement them. So for those struggling with that also, and for myself, this post is for you.

Authentication

Authentication was explained to me this way, and it's a common way of explaining it because it sticks:
Authentication is like going to the club and once your ID is checked, you receive a wristband or a stamp. After that, you can come and go from the club, or order drinks, without getting your ID checked because those working there can see you have the wristband proving that you are old enough.

Authentication is how your application can verify that the user is who they say they are and is already allowed to be there.

Authentication in Rails

Let's go through a simplified login process.

1) The user will fill in a login form on the front end with, for simplicity purposes, just a username.

2) On submit, a POST request will be sent to /login on the Rails backend

post "/login", to: "sessions#create"
Enter fullscreen mode Exit fullscreen mode

3) In a SessionsController we will set a cookie on the user's browser by using the ID of the user in the session hash

class SessionsController < ApplicationController
  def create
    user = User.find_by(username: params[:username])
    session[:user_id] = user.id
    render json: user
  end
end
Enter fullscreen mode Exit fullscreen mode

With these steps in place, our user is logged in and the Rails backend has a way of identifying the user by setting the sessions hash:

session[:user_id] = user.id
Enter fullscreen mode Exit fullscreen mode

We would also need to make sure that the front end is saving the logged-in user's information which can be done using state. However, if there is a page refresh, the backend has the session information, but the state is lost, so we have to reach into the backend and get the user info to set state. Here is how:

1) Make a route that will retrieve the user data.

get "/me", to: "users#show"
Enter fullscreen mode Exit fullscreen mode

2) Write a show controller action in the UsersController that will find the user using the session hash. (Remember to add error handling)

class UsersController < ApplicationController
   def show
       user = User.find_by(id: session[:user_id])
       if user
           render json: user, status: :ok
       else
           render json: { error: "Not Authorized" }, status: :unauthorized
       end
   end
end
Enter fullscreen mode Exit fullscreen mode

3) On application load, set the user to the user information that has been fetched. (Remember to add error handling)

function App() {
  const [user, setUser] = useState(null);

  useEffect(() => {
       fetch('/me')
           .then(r => r.json())
           .then((userData) => {
               if (!userData.error) {
                   setUser(userData)
                   fetchTrails()
                   setLoggedIn(true)
               }
               else {
                   console.log(userData.error)
               }
           })
   },[])
Enter fullscreen mode Exit fullscreen mode

Our user now has their virtual wristband on and doesn't need to "re-ID" until they completely log out.

Speaking of Logging Out

Logging out is simple, all that you need to do is...

1) Add a delete route.

delete "/logout", to: "sessions#destroy"
Enter fullscreen mode Exit fullscreen mode

2) Add a destroy controller to the sessions controller.

def destroy
  session.delete :user_id
  head :no_content
end
Enter fullscreen mode Exit fullscreen mode

3) And lastly perform the front-end functionality by setting the setUser back to null and any other log-out functionality you might have.

This will then terminate the "wristband" that the user has and they will have to re-authenticate to get back into the application club.

Authorization

To continue on the previous analogy, let's say this bar is 18+. You need to be 21 to drink, so at the entrance, you get two wristbands if you are above 21, one to be admitted in and the other for drinks. Meanwhile, 18-20-year-olds only get one wristband for admittance.

Authorization is allowing certain users permission to access specific routes. This could be useful for applications with premium subscriptions, or applications used by managers and employees. Different types of users need different types of access.

Authorization in Rails

To authorize, or not authorize, a user, you want to create a method that your controllers can refer to that says, "do not authorize unless there is a session id".

class ApplicationController < ActionController::API
  before_action :authorize

  def authorize
    return render json: {error: "Not authorized"}, status: :unauthorized unless session.include? :user_id
  end

end
Enter fullscreen mode Exit fullscreen mode

I like to put my authorization method in the ApplicationController so that all other controllers that inherit from it have access.

You might be wondering what before_action is. It is a call to ActionController's class method before_action. It is a filter method that runs before any actions in that controller.

before_action :authorize
Enter fullscreen mode Exit fullscreen mode

Now if I wanted a teaser for my application where anyone can look at it, but can't partake in any of the cool features, I could include something called skip_before_action on the index action. This allows those not logged in or those who don't have an account to see the index data but not have the ability to do anything with it.

class Controller < ApplicationController
  skip_before_action :authorize, only: [:index]

end
Enter fullscreen mode Exit fullscreen mode

Back to our analogy, the before_action and skip_before_action are easy ways to allow those over the age of 21 to order drinks and those under the age to just be there and not order a drink without any need to explicitly check ID again.

Key differences between Authorization and Authentication

After examining Authorization and Authentication, we can conclude some of their differences.

  • Authentication is to ensure you are who you say you are and can use the application freely in one session without having to show your credentials

  • Authorization is ensuring you, and other users, are authorized to have access to what you are supposed to, or not supposed to.

  • Authentication uses sessions

  • Authorize uses before_action and skip_before_action

To conclude

Grasping the fundamental concepts of Authentication and Authorization in Rails is crucial for building secure and functional web applications. The purpose of Authorization is to define what users are allowed to do within the application and ensure users have appropriate permissions for specific actions and resources. Meanwhile, Authentication is for verifying the identity of users and ensuring they are who they claim to be.

Utilizing both Authentication and Authorization in your web applications will allow you to protect your application from unauthorized access and guard sensitive user data from cybercrime. Wherever you are in your software journey, understanding the distinction between Authorization and Authentication, as well as their implementation is extremely important to building secure software.

Happy coding!

Top comments (0)