Rails 7.1 - authenticated_by

Rails provides has_secure_password class method to store passwords securely. You need to have password_digest attribute in your model to get it working.

For example, if you have a user model

class User < ApplicationRecord

The migration for user model looks like

class CreateUsers < ActiveRecord::Migration[7.0]
  def change
    create_table :users do |t|
      t.string :email
      t.string :password_digest


Now if you authenticate the user using authenticate method

Before Rails 7.1

User.find_by(email: params[:email])&.authenticate

For the above code, there are three cases

  1. If the user doesn't exist it just returns nil

  2. If the user exists and the password doesn't match it will return false

  3. If the user exists and the password match it returns user

In scenarios where a user exists, the process takes an extended duration in contrast to situations where the user does not exist. This time discrepancy can potentially be exploited by an attacker to deduce the presence of a valid username. Subsequently, the attacker could proceed to test various compromised passwords (sourced from other platforms) for unauthorized access. This technique is commonly referred to as timing-based enumeration attacks.

In Rails 7.1

authenticated_by method has been introduced. in this Pull Request https://github.com/rails/rails/pull/43765/files

User.authenticated_by(email: “test@example.com”, password: “password123”)

It will always take the same amount of time whether the user exists or does not exist

Unlike authenticate it always returns nil for non-existing users or for unmatched passwords and it will raise an exception if we don't provide email or password






Did you find this article valuable?

Support Rashmi Yadav by becoming a sponsor. Any amount is appreciated!