Rails 7.1: Generate tokens for specific purposes with generates_token_for

Rails 7.1 introduces a new method, generates_token_for, which allows you to generate tokens for specific purposes. These tokens can expire and can also embed record data. When using a token to fetch a record, the data from the token and the current data from the record will be compared. If the two do not match, the token will be treated as invalid.

This method is useful for generating tokens for a variety of purposes, such as:

Authentication: A token can be used to authenticate a user in an API.

Authorization: A token can be used to authorize a user to access a resource or perform an action.

Identification: A token can be used to identify an object uniquely.

Single-use tokens: A token can be generated for a single use, such as a password reset token.

To use generates_token_for, you first need to define the purpose of the token. You can do this by passing a symbol to the generates_token_for method. For example, to generate a password reset token, you would pass the symbol :password_reset.

You can also optionally specify an expiration time for the token. If you do not specify an expiration time, the token will never expire.

Finally, you can pass a block to the generates_token_for method. This block will be used to generate the token. The block can access the record for which the token is being generated.

Here is an example of how to use generates_token_for to generate a single-use password reset token:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
class User < ActiveRecord::Base
  has_secure_password

  generates_token_for :password_reset, expires_in: 15.minutes do
    # `password_salt` (defined by `has_secure_password`) returns the salt for
    # the password. The salt changes when the password is changed, so the token
    # will expire when the password is changed.
    password_salt&.last(10)
  end
end

user = User.first
token = user.generate_token_for(:password_reset)

User.find_by_token_for(:password_reset, token) # => user

user.update!(password: "new password")
User.find_by_token_for(:password_reset, token) # => nil

In this example, the generates_token_for method is used to generate a password reset token that expires after 15 minutes. The token is generated using the last 10 characters of the user’s password salt. This ensures that the token will expire when the user changes their password.

To use the password reset token, we simply call the find_by_token_for method with the purpose of the token and the token itself. If the token is valid, the find_by_token_for method will return the user record associated with the token. Otherwise, the method will return nil.

Once the user has reset their password, we should invalidate the password reset token by calling the update! method on the user record and setting the password_reset_token attribute to nil.

Benefits of using generates_token_for

There are a number of benefits to using generates_token_for to generate tokens, including:

Security: Tokens generated with generates_token_for are more secure than tokens generated with other methods, such as signed_id. This is because tokens generated with generates_token_for can embed record data. This data can be used to verify the authenticity of the token and to prevent it from being reused.

Flexibility: generates_token_for is a very flexible method. You can use it to generate tokens for a variety of purposes, including authentication, authorization, identification, and single-use tokens.

Ease of use: generates_token_for is very easy to use. To generate a token, you simply need to call the generates_token_for method and pass in the purpose of the token and a block to generate the token.