Multiple token authentication with Devise & redis


I’ve been developing on Rails for quite some time now and i continue to realize the power and benefits this framework gives you. In Rails, when you want to get a new capability into your application, you first try to find something OOTB. The best gem for the job is usually the one that gives you everything you want in one place. The variety and maturity of community plugins provide Rails developers with the ability to easily create rich web applications. But what happens when you find a plugin that gives you 95% of what you want and you need to add the 5% yourself ?
I found Devise to be that plugin. This great plugin gave me everything i needed in order to authenticate users in my application except one feature.
Using Rails, i have developed an api and i was looking for a way to authenticate users in different clients simultaneously and let every client work dependently of the others. Devise only gives you 2 forms of authentication: database (using cookies) and token based authentication. I wanted to use the database authentication for users who login with email and password and the token authentication for those who wanna use the api from mobile devices and other applications and want to just login with a token.
Database authentication using Devise was pretty easy. With the tokens i had 2 requirements:
- The token had to be regenerated on every login (for security reasons).
- Logging out of the api had to revoke the token.
The problem i had was that logging in from 2 devices simultaneously was impossible because (the numbers correlate to the requirements numbers above):
- One client login always revokes the token for the other.
- Logging out from one client revokes the token for the other.
I figured i had to generate a token for each user+client. That token will “live” for as long as the user is logged in on a specific client. In order to accomplish that and still use Devise i had to expand its capabilities to support my multiple tokens philosophy. I also selected redis as my storage for the tokens (I won’t get down to details on “why redis” in this post)
So lets go down to the code:
First, i had to create a class that handles the interaction with redis. I created a file under “lib” and called it authentication_tokens.rb. In my implementation, every token is added to redis with the prefix “auth_token:”. You can also notice that i’ve put a 24.hours expiration time for a token (24 hours of no activity with the token).
class AuthenticationTokens
include Singleton
def initialize
@redis ||= Redis.new(:host => "localhost")
end
def AuthenticationTokens.finalize(id)
@redis.quit
end
# generate authentication token using the given email and save it in redis
# the generated token will have a field "user_id" in order to identify the associated user later
def generate(email, user_id)
token = Utils::gen_token(email)
key_s = token_key token
@redis[key_s] = user_id
@redis.expire key_s, 24.hours
token
end
# renewing expiration timeout
def touch(token)
@redis.expire token_key(token), 24.hours
end
# deletes the token
def revoke(token)
@redis.del token_key(token)
end
def token_val(token)
@redis.expire token_key(token), 24.hours
@redis[token_key(token)]
end
private
def token_key(token)
"auth_token:#{token}"
end
end
I also created a Devise strategy to handle my multiple tokens authentication logic inside devise. The strategy is kept in multiple_tokens_strategy.rb under “config/initializers”. The strategy uses the previously created class in order to check with redis if the token exists.
module Devise
module Strategies
class MultipleTokensStrategy < Devise::Strategies::Base
def valid?
params[:auth_token]
end
def authenticate!
user_id_str = AuthenticationTokens.instance.token_val(params[:auth_token])
if user_id_str
user = User.find(user_id_str.to_i)
if user
user.after_database_authentication
success!(user)
end
end
if (!(params[:user]) && !halted?)
fail!("Invalid authentication token.")
end
end
end
end
end
The newly created strategy needs to be added to the initializer “devise.rb”
Devise.setup do |config|
...
config.warden do |manager|
manager.strategies.add(:multiple_tokens_strategy, Devise::Strategies::MultipleTokensStrategy)
manager.default_strategies(:scope => :user).unshift :multiple_tokens_strategy
end
end
After creating the strategy and registering it with Devise we just need to generate the token when the user logs into the system (through the api or regular signin). In order to do that we’ll have to override Devise’s SessionsController as explained in many places on the web (for example: http://stackoverflow.com/questions/8070320/rails-3-override-devise-sessions-controller). After overriding Devise’s SessionsController, i overridden 3 actions: “create” & “require_no_authentication” & “destroy”. I copied Devise’s original code and added my functionality inside. Inside the code you’ll see comments with what i did exactly:
class SessionsController resource_name,
:recall => ("#{controller_path}#new" : "sessions#authentication_failure_json"))
# This code is copied from Devise
set_flash_message(:notice, :signed_in) if is_navigational_format?
sign_in(resource)
# if the winning strategy is MultipleTokensStrategy than don't replace
# auth_token, otherwise generate a token for the user.
if warden.winning_strategy.class != Devise::Strategies::MultipleTokensStrategy
auth_token = AuthenticationTokens.instance.generate resource.email, resource.id
else
# we assume that params[:auth_token] exists b/c winning strategy is MultipleTokensStrategy
auth_token = params[:auth_token]
end
# keep the token in the session for future reference
session[:auth_token] = auth_token
# Here i respond to different formats.
respond_to do |format|
format.html { redirect_to root_path }
format.json { render :json => resource }
end
end
# This action is called to check if an authentication is actually needed.
def require_no_authentication
# This code is copied from Devise
no_input = devise_mapping.no_input_strategies
args = no_input.dup.push :scope => resource_name
if no_input.present? && warden.authenticate?(*args)
resource = warden.user(resource_name)
flash[:alert] = I18n.t("devise.failure.already_authenticated")
# My code here
# We generate a new token even if no authentication is required b/c we don't
# know what token to return if the user is logged in already and asks to
# login again ONLY with user and password than (in my implementation) he
# actually "asks" for a new token.
# If the user is logged in already and asks to login again with
# a valid auth_token than that token is returned.
auth_token = params[:auth_token] || session[:auth_token] || AuthenticationTokens.instance.generate(resource.email, resource.id)
session[:auth_token] = auth_token
# Here i respond to different formats.
respond_to do |format|
format.html { redirect_to after_sign_in_path_for(resource) }
format.json { render :json => resource }
end
end
end
# This action is called on logout.
def destroy
# My code here.
# I look for the user with the given token. If he exists than he gets logged
# out, if not than the current_user is logged out.
auth_token = params[:auth_token]
if auth_token
user_id_str = AuthenticationTokens.instance.token_val(auth_token)
if user_id_str.blank?
if current_user
@user = current_user
else
respond_to do |format|
format.html { redirect_to root_path }
format.json { render :json => {:errors => "Already logged out!"} }
end
return
end
else
@user = User.find(user_id_str.to_i)
AuthenticationTokens.instance.revoke auth_token
session[:auth_token] = nil
end
else
@user = current_user
end
# This code is copied from Devise
sign_out(@user)
# Here i respond to different formats.
respond_to do |format|
format.html { redirect_to root_path }
format.json {
render :status => 200, :json => { :email => @user.email } }
end
end
# This function supports returning error message on failure to authenticate.
def authentication_failure_json
return render :json => { :errors => alert }
end
end
That’s it! Quite an effort to get it done but with that you’ll have the ability to connect with multiple clients to your rails application without then interfering each other.
Startup life. The bad days. (*) « 21st century geek
Great post !
Ruby Glazed: git-ify your command line!
In a nutshell:
Run
bash < <(curl -s https://raw.github.com/gurdotan/gitify/master/gitify )and get lots of nice command line goodies for git (test only on Ubuntu). Note: running this will not include the utilities detailed below in sections 1 & 5.In detail:
I’ve been working with git a lot…
Source: rubyglazed
Windows Phone - Will history repeat itseft ?!
From beginning of time, there’s one rule that no one can disagree with: “History repeats itself”. Over and over again we see how events repeat themselves in different domains of our lives. Empires come and go, social revolutions takes down dictators and new eras of blossoming creativity always follows grimy times of wars and ignorance. It looks like things change but everything stays the same. There’s nothing new under the sun. The same thing is going to happen to the long lasting battle on operating systems for mobile phones.
Bill Gates started the major professional road of his life working for Apple, understanding its ways and coming out with his own ideas based on what he learned. He based his company on ideas that were created by others and managed to invent products that’ll suit the majority of people based on what he learned. Gates shaped Microsoft in his image so it’s not a surprise we can see the giant corporation doing the same over and over again. They almost never invented something completely new and when they tried to do that they almost always failed.
Knowing how to be #2 or #3 or less until the right moment pops out is a skill that requires patience, ease of mind and cleverness that Gates and his teammates proved to have made a way of life. Doing exactly that with Windows, Xbox, Zune, .NET and other products by copying ideas from other companies or just buying them shows how Microsoft understands how to make successful technological products that will eventually be used by the majority of their market.
Don’t be surprised if Microsoft is going to pull it off again with Windows Phone. Apple started the new era of smart phones (as they did with personal computers) and Google’s android is a great iPhone killer but when MS wants to play he knows how to win better than anyone else. Playing their cards right, Gates’ gang can do what they do best and if that happens the others don’t have a chance.

Apple and Google are not going to give up in this fight. Apple already gives mobile developers great tools and APIs. They are going to keep giving their groopies little drops of heaven with every new release of iOS. Google’s Android started as open as it can get and it’s starting to close down and look like a mature mobile OS that actually looks and feels nice. They even show signs of improvement in their IDEs and APIs so mobile developers might find it enjoyable to develop android apps one day. Both companies have made quite a journey with their OSs and they learn as they go. It’s always hard to fight against experience.

That been said, look at Microsoft, they have the best dev tools for their dev technologies, they provide prestige and usability and they got NOKIA which is a major league player in the old cell phones league. Windows phone is cool, fun, friendly and going to be open just enough for people to get what they want. Microsoft watched the game from the bench. They played a bit on the regular phones market with the failed Windows Mobile BUT they got the essence of the smartphone game: make it fancy and fully featured but keep it simple and easy to understand. If they’ll find the balance between customization and usability they might win another one for the fully packed trophy closet.
According to what we’ve already seen and to Windows Phone’s leaked road-map, Microsoft is taking it slow. They know the market is still developing so they take small and cautious steps. Everyone in this market is trying to figure out what people really want from their smartphone. We know that people want it to be versatile and creative but they also need it to be simple and friendly in order for them to be productive. Close or Open, Simple or Weary … where’s the balance?!
It’ll be interesting to see what’ll happen in 2012. I’m guessing that 2011 will continue. Android will continue to gain power and new iOS features will be presented. Taking a look a couple of years ahead i think things are going to change. Will history repeat itself? i say YES.
Facebook keeps you alive !
Why people use Facebook or Twitter? Why people share videos, pictures and thoughts online? What pleasure do we get from the basic action of uploading a photo or sharing an idea? In the same breath one can also ask why people participate in reality shows, want to be a celebrity or even skydive? It all lies in the urgent need of every human being to feel alive.

Human average life expectancy in present times is about 67 years. We see people come and go from our world. Some of them leave their mark and some of them just enjoy the ride. But everyone want to feel their existence, they want to get the validation that they are here. The basic knowledge that we walk on this world and enjoy its perks makes us happy and fills us with a sense of fulfillment.
When you upload a photo to Facebook from your last trip to NYC, you get excited. The excitement doesn’t come from clicking the mouse or commenting “I love shopping in NYC” on your keyboard. It comes from the feeling that in a few minutes (or hours) you’ll get the acknowledgement that you’re alive. When you know that people will see your photo and acknowledge your existence you feel alive. When your friend writes a response comment like “Great photo, you look amazing!” you get the feedback you needed. The validation that you’re here.

People are like machines. They are an input-output device. When someone tells you you’re ugly than you’ll feel bad. When someone will hug you you’ll feel good (unless he smells bad). We live our day to day occurrences and react to them. That’s why we can’t feel alive without people (or other outer objects) telling us we’re alive. That’s what Mark Zukerberg and his fellow social services CEOs know. They realized that as long as they give you the feeling that you’re alive they will keep you their “friend”.
You can see a clear difference between Facebook and Google+ and it’s not the social circles. Facebook is full of active users. Your Facebook wall is vivid while your Google+ stream is dull as dishwater. You know there’s a better chance that someone will notice you when you share something on Facebook. And if there’s a better chance someone will notice you than there’s a better chance they’ll give you the validation you need. The validation of existence.
So the next time you publish something on Facebook or twitter or the next time you check-in in Startbucks and become the mayor of your neighborhood coffee shop know that you’re just trying to stay alive.
Devise sign_in using JSON
I was trying to create a RESTful web-service using Rails 3.0. I wanted my web-service to communicate with “the world” using JSON. I also wanted my web-service to use two security methods:
- Database security - using the server session.
- Token security - in order to allow users to login to the api using tokens.
Devise answered my security needs. It was also pretty easy to add JSON responses b/c rails pretty much gives it to you OOTB. I even found it easy to generate json templates using the great acts_as_api gem. BUT when i tried to figure out how to actually do devise’s sign_in using JSON request/response i hit a wall.
I found this great post by Jesse Howarth that explains how to do the actual sign_in and with some alterations it worked fine. Howarth fails to explain one thing: How to return devise’s error messages when sign_in fails.
In order to achieve that i had to override SessionController’s create action and add an authentication_failure method.
def create
resource = warden.authenticate!(:scope => resource_name, :recall => “sessions#authentication_failure”)
set_flash_message(:notice, :signed_in) if is_navigational_format?
sign_in(resource)
resource.reset_authentication_token!respond_to do |format|
format.json { render :status => 200, :json => { :success => true, :auth_token => resource.authentication_token, :user => resource } }
endend
def authentication_failure
return render:json => {:success => false, :errors => alert}
end
From authentication_failure you can see that the actual failure message is kept in the variable alert.
Note: In create action i decided to reset the authentication token when the user logs in. It’s up to you if you want to keep this functionality.
Sometimes you have to do some hacking in order to get your desired solution.
acts_as_api … :meta => @data
I’ve been working with the fantastic Rails for a few months now and i’m still discovering the wonders of it.
In order to create different representations of JSON for my REST api i picked acts_as_api. As the author of this plugin describes, it’s really easy and fun to use. When a colleague of mine asked me to provide him with meta information about returned data i found another cool feature inside it.
In our system we deal with plenty of entities. For the purposes of this post i’ll discuss one of them: Review.
My colleague is using my api to retrieve reviews. He used to call:
And got:
{“review”:[{“id”:1,”title”:”Great iadea”,”comment”:”I love your idea. You’re a great thinker.”,”rating”:4.5},{“id”:2,”title”:”Great idea”,”comment”:”I love your idea. You’re a great thinker.”,”rating”:4.5}]}
acts_as_api code (inside review.rb) was:
class Review < ActiveRecord::Base
…
acts_as_api
api_accessible :api_v1 do |t|
t.add :id
t.add :title
t.add :rating
t.add :comment
end
end
reviews_controller.rb was:
class ReviewsController < ApplicationController
def index
respond_to do |format|
format.json { render_for_api :api_v1, :json => @reviews }
end
end
end
The returned JSON representation is perfectly and easily created by acts_as_api.
BUT than my colleague wanted to retrieve the total number of reviews along with the list of reviews. I started by the obvious (but worse) solution and than found the better solution.
The obvious (but worse) solution:
acts_as_api lets you add special functions to your representation so i just added “total_reviews” to the list of returned parameters:
I revised acts_as_api code (inside review.rb):
class Review < ActiveRecord::Base
…
acts_as_api
api_accessible :api_v1 do |t|
t.add :id
t.add :title
t.add :rating
t.add :comment
t.toal :total_reviews
end
def total_reviews
Review.all.count
end
end
The returned JSON was:
{“review”:[{“id”:1,”title”:”Great iadea”,”comment”:”I love your idea. You’re a great thinker.”,”rating”:4.5,“total_reviews”:2},{“id”:2,”title”:”Great idea”,”comment”:”I love your idea. You’re a great thinker.”,”rating”:4.5,“total_reviews”:2}]}
That’s not a bad solution but the total number of reviews is put in every single review.
The better solution:
I switched acts_as_api code in the model back to the initial code and went to reviews_controller.rb:
class ReviewsController < ApplicationController
def index
respond_to do |format|
format.json { render_for_api :api_v1, :json => @reviews, :meta => {:total => Review.all.count} }
end
end
end
And … The magical returned JSON was:
{”total”:2, ”review”:[{“id”:1,”title”:”Great iadea”,”comment”:”I love your idea. You’re a great thinker.”,”rating”:4.5},{“id”:2,”title”:”Great idea”,”comment”:”I love your idea. You’re a great thinker.”,”rating”:4.5}]}
acts_as_api is taking care of the meta data and putting it in front of the returned data.
I love it !
My first post EVER !
After year of reading other people’s blogs and thinking of what they have to say, i decided to share my ideas and findings in many aspects of my life.
Happy reading :)

