Rails 7.1 adds ActiveRecord::Base::generates_token_for
Rails 7.1 introduced the ActiveRecord::Base::generates_token_for
method,
which provides a convenient way to generate
and
validate tokens for various use cases in Rails applications.
This feature streamlines token generation
and
validation,
bolstering the security
and
user experience of our application.
It facilitates the implementation of features like password reset
,
email verification
,
and
other functionalities that rely on one-time tokens.
Before Rails 7.1
Before Rails 7.1, signed_id was used to generate tokens. It is primarily used to prevent tampering or unauthorized access to data by generating a secure digital signature.
The primary usage of signed_id
is as below:
user = User.last
# signed_id for last user
signed_id = user.signed_id
=> "eyJfcmFpbHMiOnsibWVzc2FnZSI6Ik9RPT0iLCJleHAiOm51bGwsInB1ciI6InVzZXIifX0=--ab2c33729462c2c1febe02b4a46ebb8c5f024c292b62987c3323049a591aaab6"
# Find user with signed_id
User.find_signed(signed_id)
=> #<User:0x00000001156c57d0 id: 9, name: "[email protected]".....
The validity period for a signed ID is specified during its generation using the
signed_id(expires_in: 15.minutes)
instance method.
If the validity period has passed before attempting to find a record using a signed ID,
the signed ID will no longer be valid
and
will return nil
.
user = User.last
# signed_id for last user
signed_id = user.signed_id(expires_in: 15.minutes)
=> "eyJfcmFpbHMiOnsibWVzc2FnZSI6Ik9RPT0iLCJleHAiOm51bGwsInB1ciI6InVzZXIifX0=--ab2c33729462c2c1febe02b4a46ebb8c5f024c292b62987c3323049a591aaab6"
# after 5 mins
User.find_signed(signed_id)
=> #<User:0x00000001156c57d0 id: 9, name: "[email protected]".....
# after 15 mins
User.find_signed(signed_id)
=> nil
While signed IDs provide a secure way to authenticate users, they cannot track the usage of tokens. Therefore, if a token is meant for single use, it must be stored and monitored in a database until it expires to prevent unauthorized reuse.
In Rails 7.1
Rails 7.1 adds the ActiveRecord::Base::generates_token_for
method.
The generates_token_for
method allows embedding data from a record into the generated token.
When the token is used to retrieve the corresponding record,
the data stored in the token is compared with the current data of the record.
If there's a mismatch,
the token is deemed invalid,
similar to an expired token.
class User < ActiveRecord::Base
has_secure_password
generates_token_for :password_reset
end
user = User.last
token = user.generate_token_for(:password_reset)
User.find_by_token_for(:password_reset, token)
=> #<User:0x00000001156c57d0 id: 9, name: "[email protected]".....
The generated tokens never expire;
to specify the expiry time,
you can pass the expires_in
option.
class User < ActiveRecord::Base
has_secure_password
generates_token_for :password_reset, expires_in: 1.day
end
This method offers several advantages over manually generating and validating tokens:
Simplicity: It simplifies the process of generating and validating tokens, reducing the amount of code required and making it easier to maintain.
Security: It incorporates security measures to prevent token forgery and ensure the integrity of tokens.
Flexibility: It allows for embedding additional data in the token, which can help validate specific conditions or identify its purpose.
Expiration: It supports setting an expiration time for tokens, ensuring that tokens become invalid after a specified period, enhancing security and preventing misuse.
Consistency: It promotes consistency in token generation and validation across the application, reducing the risk of errors.
To know more about this feature, please refer to this PR.