Tag Archives: digging through github to find the error

How to authenticate one scope from another with Devise

My app has multiple kinds of users, some of which belong to others. It's a result of having many disparate login systems, one per community, and offering the ability to merge them together. This is how I auth the One True account from the local account.

I banged my head on this for a while: what I wanted to do was to just take the

user.one_true_master_account

model and go from there, but the current_#{scope} helpers aren't available in a devise strategy. So I did some digging and figured out how to do it with warden without dragging in more than I had to. (this is in config/devise.rb)

FromUserAuthentication
  class FromUserStrategy < Devise::Strategies::Authenticatable
    def valid?
      # I'd have to authenticate to figure out if it's valid anyway, but I'd
      # rather run it in the devise auth chain 
      true
    end

    def mapping
      Devise.mappings[:one_true_master_account]
    end

    def authenticate!
      # env here is provided in the superclass, it's that enormous hash that 
      # gets passed to middlewares
      user = env['warden'].authenticate(scope: :one_true_master_account)
      if user
        one_true_master_account = user.one_true_master_account
        success!(one_true_master_account)
      end
    end
  end
end

Then I registered it with the various subsystems that needed to know about it

Warden::Strategies.add :from_user_authentication,
                       FromUserAuthentication::FromUserStrategy
Devise.add_module :from_user_authentication, strategy: true

Then I added it as a default strategy for that scope.

Devise.setup do |config|
  config.warden do |manager|
    manager.default_strategies(:some_other_auth_strategy, :another_auth_strategy,
                               :from_user_authentication,
                               scope: :one_true_master_account)
  end
end

This last one is necessary only because of a quirk in our system. Warden can look at the mapping function to figure out which strategies are appropriate in most other situations, but we wanted to have our strategies in different orders for different models.