It is a common requirement to have a single sign on for multiple software services provided by a company, something like google account with multiple google services like gmail,docs,google+ . In order to do this it would be best to have a RESTful application responsible for authentication and have all other services authenticate against this application.
To authenticate users of our rails application against an external API we add a custom authentication strategy to devise. Devise is a flexible authentication solution for Rails based on Warden. Warden uses the concept of cascading strategies to determine if a request should be authenticated. Warden will try strategies one after another until either, – One succeeds – No Strategies are found relevant – A strategy Fails.
These are the steps to add custom authentication strategy.
1. Create your own strategy implementation inheriting from Devise::Strategies::Base
FromSession < ::Devise::Strategies::Base
# this strategy is only valid if there is a url_token
# in the params hash.
# lookup session data with external api
session_data = get_session_data_from_api(params[
# check if token was valid and authorise if so
# session lookup failed so fail authentication with message from api
# we got some valid user data
- The HTTP request enters the rack stack.
- Warden gets the request and forwards it in the rack stack, adding an environment variable “warden” that points to an authentication proxy.
- The request gets dispatched to the rails controller, which may call authenticate_user! from a filter. This is an alias for request.env[‘warden’].authenticate!(:scope => :user).
- The warden proxy picks an authentication strategy. Any strategy for which valid? returns true is tried.
- When authentication succeeds, a user object is returned to the controller. When it fails, the symbol :warden is thrown down the stack, and caught by the warden rack application. The latter will return a response, which is a redirect to the login page by default. This can be overridden by calling warden.custom_response!.