Q:

Switching between web and touch interfaces on Facebook login using Omniauth and Rails 3

The situation:
Using Rails 3 and OmniAuth, I have an app that authenticates using the Facebook strategy. This app has been built to work equally-well for web and mobile interfaces (ala Jquery-Mobile).
The challenge is to get OmniAuth to provide the mobile version of Facebook's login screen to mobile devices and the web version to desktop devices.
I've hacked together a solution which I'll put as an answer.

A:

Actually, since OmniAuth::Strategies are already Rack middleware, its even simpler. Just override the request_phase method and check the @env instance variable present in the strategy for a mobile user_agent:
module OmniAuth
  module Strategies
    class Facebook < OAuth2

      MOBILE_USER_AGENTS =  'webos|ipod|iphone|mobile'

      def request_phase
        options[:scope] ||= "email,offline_access"
        options[:display] = mobile_request? ? 'touch' : 'page'
        super
      end

      def mobile_request?
        ua = Rack::Request.new(@env).user_agent.to_s
        ua.downcase =~ Regexp.new(MOBILE_USER_AGENTS)
      end

    end
  end
end

A:

For modern devise / omniauth (>= 1.0) use this in your config/initializers/devise.rb:
FACEBOOK_SETUP_PROC = lambda do |env|
  request = Rack::Request.new(env)
  mobile_device = request.user_agent =~ /Mobile|webOS/i
  request.env['omniauth.strategy'].options[:display] = mobile_device ? "touch" : "page"
end

config.omniauth :facebook, FACEBOOK_APP_ID, FACEBOOK_APP_SECRET,
  :scope => 'email,offline_access', :setup => FACEBOOK_SETUP_PROC,
  :client_options => { :ssl => { :ca_file => Rails.root.join("config/ca-bundle.crt").to_s }}

