Tutorial: Casual Authentication in Rails
My latest site uses, what I call, “Casual Authentication“. It’s best used for sites where the risk of an intruder getting in to a user’s account isn’t huge and is of little value to an intruder. For example, a to do list, or other small web app without sensitive data. The basic way it works is that:
- The users signs up with one click. This takes them to a personalised page.
- At this point a unique 7-digit Key is generated and assigned to the user
- The Key is then used by the user to log in to their page, either by entering their key in a textbox on your home page, or by routing URLS, for example:
www.foosite.com/6837349 will log the user in if their key is 6837349
The main advantage of this approach is that it is quick to sign up users and quick for them to sign in on return visits. If required, you could introduce another level of authentication, for example, asking for their name or e-mail address after they’ve entered their key.
Here’s how to implement the basic functionality.
The User Model
To prepare our User model to support casual authentication, add the following methods:
class User < ActiveRecord::Base
validates_presence_of :access_key
validates_uniqueness_of :access_key
# override superclass initialize so that a new
# access_key is always generated for a user
def initialize()
super()
self.access_key = User.generateKey
end
# used to sign a user in
def self.authenticate(key)
# find the user with this key
u=find(:first, :conditions=>["access_key = ?", key])
return nil if u.nil?
return u
nil
end
def self.generateKey
# key must be between
@minKey = 1000000;
# and
@maxKey = 9999999
# now we generate a random number between minimum and maximum
@potentialKey = @minKey + rand(@maxKey - @minKey)
# check key not in use by another user
# if so generate a new key recursively until a
# unique one is found
if User.find(:first, :conditions => ["id = ?", @potentialKey])
@potentialKey = self.generateKey
end
return @potentialKey
end
# other User model logic...
end
Note that the key here is a 7-digit number between 1,000,000 and 9,999,999. Obviously to decrease the chance of someone finding an active account, or to reduce the risk of collisons further, you can increase the upper bound (@maxKey) of your key set.
The migration for the User model is as follows:
class CreateUsers < ActiveRecord::Migration
def self.up
create_table :users do |t|
t.column :access_key, :integer
# other fields for your user model...
end
end
def self.down
drop_table :users
end
end
You only need the access key field, as well as any other fields you store about your users, such as their name or location.
The User Controller
Here are the signup and signin methods in the User controller:
class UserController < ApplicationController
# signs up a new user
def signup
@user = User.new()
# save the user to db
if @user.save
# sign in the new user
session[:user] = User.authenticate(@user.access_key)
# confirmation and instructions to the user that sign up was successful
flash[:message] = "Signup successful! Your key is <b>" << @user.access_key.to_s << \
"</b>, make sure you note it down! <br/>You can access the site directly <b>" \
"<a href='http://www.foosite.com/" << @user.access_key.to_s << "'>" \
"by bookmarking this link</a></b>"
# signed up so take to their home page
redirect_to :controller => "user", :action => "home"
else
logger.warn("Saving new user failed")
flash[:warning] = "Signup unsuccessful"
# either redirect_to_stored or to some other page
redirect_to :action => 'front'
end
end
# action called to sign a user in
def signin
if session[:user] = User.authenticate(params[:access_key])
flash[:message] = "Login successful"
redirect_to :controller => 'user', :action => 'home'
else
flash[:warning] = "Login unsuccessful"
end
end
end
Signing up new users
It’s easy, trust me. Just add this where needed:
<%= link_to 'Click here to create an account', :controller => 'user', :action => 'signup' %>
Signing In Users
They can in sign in via www.foosite.com/[theirkey], you can implement this by adding the following to your routes.rb file:
ActionController::Routing::Routes.draw do |map|
map.connect ':access_key', :controller => 'user', :action => 'signin'
# rest of your routes...
Or by providing a text box that they enter their key in:
<% form_tag :controller => 'user', :action => 'signin' do %>
<br/>
<p><label for="user_login">Key:</label><br/>
<%= text_field_tag('access_key', '', :size => '8', :maxlength => '8') %></p>
<br/>
<p><%= submit_tag "Sign in" %></p><br/>
<%= link_to 'Click here to create an account', :controller => 'user', :action => 'signup' %>
<% end %>
The Usual Stuff
You probably want to introduce some logic so that users who are already signed in don’t get your “Click here to create an account” link and, instead, see some sort of other links.
You can check if a user is signed in from anywhere in your application by adding the current_user helper below.
There is also a helper to retrieve the current user object, and a further helper to derive the URL for the user to bookmark to access their account directly:
class ApplicationController < ActionController::Base
# return the current user
helper_method :current_user
def current_user
session[:user]
end
helper_method :logged_in?
def logged_in?
return session[:user] ? true : false
end
# the users key to enter the site
helper_method :get_bookmark
def get_bookmark
return 'www.foosite.com/' << current_user.access_key.to_s
end
end
The End
Thats it. I hope that works for you as a quick, easy and convenient method of casual user authentication. Let me know if you have an comments or suggestions.

Whatever methods we use to teach skills and knowledge at the professional stage involve us in many assumptions about how we learn professional skills, knowledge and values, what we learn and why, and what we expect students and trainees to do with that learning. ,
Ganry81 said this on October 22, 2009 at 9:25 pm |