Authlogic: after the initial hype

d i g b e t h # 5
Creative Commons License photo credit: sammy may

On my rails projects, I've used restful_authentication before and I am using authlogic now. Even though I have passed the initial hesitation phase with authlogic, I can't say that I am totally sold.

What I like about authlogic is it refrains from providing any controller/view level support and handles model layer better. Instead, it provides a solid model functionality that is similar in principle to ActiveRecord and provides lots of how-to examples on how you might code your controllers/views/workflows. It does it well. Although authlogic is complemented for refraining from too much code generation, Authlogic still does a lot of magical stuff. You encounter this readily with tests. Instantiating and persisting a user will log you in! It is hard to test your User model from console since authlogic will fail if you try to instantiate User object in console. You have to jump thru hoops (include Authlogic, set proper controller reference) to get it to work.
Problem with Perishable Token:
Today I encountered another issue with authlogic realted to perishable token. According to docs, perishable tokens are useful for implementing features such as reset-password and confirm email. These functionalities are essentially similar in implementation in that application generates a token and emails url containing this token to the user's registered email address. User clicks on the url and resets his password or confirms that email is indeed his email. The implementation details are explained very well by author here.

However, it didn't work in my case. The problem, I believe, is that perishable_token changes often... too often actually. Looking side the codebase for Authlogic::ActsAsAuthentic::PerishableToken reveals this:

def self.included(klass)
  return if !klass.column_names.include?("perishable_token")
  klass.class_eval do
    extend ClassMethods
    include InstanceMethods
 
    before_save :reset_perishable_token, :unless => :disable_perishable_token_maintenance?
  end
end
def reset_perishable_token
  self.perishable_token = Random.friendly_token
end

As you can see, the token changes on each save. This can be readily verified from console:

>> u = User.find_by_email("sjain@iit.edu")
#=> #
>> u.perishable_token
#=> "6qLHkU_vBQK6rLQGy-oL"
>> u.save
#=> true
>> u.perishable_token
=> "1tlcpvc_sCGtNEfIQCt1"
>>

Everytime the user object is saved, the token changes. In a running app this could happen for any number of reasons. I wonder, if having other authlogic magic attributes like login_count, last_request_at etc. causes the instance to get saved immediately after the token was sent in email, practically overwriting the token that was critical to password-reset workflow...

Solution:
Fortunately, Authlogic allows you to take control and manage token yourself. To do this, you disable the automatic maintenance of perishable_token by authlogic as follows:

class User < ActiveRecord::Base
  acts_as_authentic
  disable_perishable_token_maintenance(true)
end

By doing this, authlogic leaves this column in database alone. You can now reset the token when you need it. Here is what my password-reset and confirm-email hooks look like then:

class User < ActiveRecord::Base
  def deliver_confirm_email_instructions!
    reset_perishable_token!
    Notifier.deliver_confirm_email_instructions(self)
  end
 
  def deliver_password_reset_instructions!
    reset_perishable_token!
    Notifier.deliver_password_reset_instructions(self)
  end
end

In addition, since we took the control of perishable_token in our hands and that it is a non-nullable field in database, we have to reset the token when a new user registers for an account on our website.

class UsersController < ApplicationController
  def create
    @user = User.new(params[:user])
    # set the token manually
    @user.reset_perishable_token
    if @user.save
      @user.deliver_confirm_email_instructions!
      flash[:notice] = "Registration successful. Please check your email to confirm your email address."
      redirect_to root_url
    else
      render :action => 'new'
    end
  end
end

Conclusion:
All in all, authlogic is a well designed authentication library. However, you can't get around the fact that authentication and its surrounding sub-features (password reset, registration, email confirmation) can get complex. When coming away from restful_authentication to authlogic you will be glad to find intuitive for its API that is very similar to ActiveRecord, configurablility to enable/disable features that you need and don't need. But, don't expect an easy ride. You are bound to have to dive into the codebase to take advantage of some of the complex features.

Related posts:

  1. ActiveRecord create_or_update based on natural-key
  2. activerecord tests: modify activerecord logging without tripping rollback convenience
  3. Griffon and a PureMVC Plugin: Some Initial Thoughts
  4. acts_without_database: Leverage ActiveRecord with Non-Database Backed Objects
  5. Rails Email Unit Testing

Comments: 2 so far

  1. You wouldn’t happen to know why authlogic’s password reset doesn’t include the reset link in the email body? This one is really messing with me. I’ve been diving into Rails to get away from all the sloppiness of other environments and am finding that at as far as Rails plugins go things are almost as bad as the environments I’m trying to get away from :-(

    Much thanks.

    Comment by Adrien Lamothe, Thursday, October 8, 2009 @ 4:59 pm

  2. Thank you.

    Users on our site can click around before confirming the email. So the confirmation link typically expired by the time the user visited their email box. This will definitely fix our problem.

    One thing I did notice:

    If a user requests 2 confirm email messages, each email has a different token (and a different link). The problems is gmail will show these in a thread. The link in the first message (which is invalid) is displayed and the link in the second message (which is valid) is obscured.

    So we are sending out the same token on all emails.
    We are invalidating the token after the user confirms rather than before the user requests the confirmation email.

    Thanks Again,
    K

    Comment by Keenan Brock, Wednesday, December 23, 2009 @ 10:24 am

Leave a comment

Powered by WP Hashcash

Launch: Pathfinder Newsletter

Topics

Search

WordPress

Comments about this site: info@pathf.com