8

The problem I'm having is that I'm using doorkeepers resource owner credential flow to authenticate a user from an iOS app. My project has two separate user models though (let's call them User and Admin). My code looks like this:

resource_owner_from_credentials do |routes|
  user = User.find_for_database_authentication(:email => params[:username])
  user if user && user.valid_password?(params[:password])
end

It works but how do I do a check for admin also? In other words I don't know if the person logging in is a user or admin - how do I check for both?

2 Answers2

11

Doorkeeper provides Scopes for this purpose (see https://github.com/doorkeeper-gem/doorkeeper/wiki/Using-Scopes)

So in your doorkeeper.rb file you can do:

resource_owner_from_credentials do |routes|
  if params[:scope].present?
    case params[:scope]
      when "user"
        u = User.find_for_database_authentication(:email => params[:email])
      when "admin"
        u = Admin.find_for_database_authentication(:email => params[:email])
    end
  else 
    #default auth
    u = User.find_for_database_authentication(:email => params[:email])
  end
  u if u && u.valid_password?(params[:password])
end  

Then for authenticate your resource (ex. Admin) you can make a request like that:

POST $HOST/oauth/token
{
  email: john@doe.com
  password: johndoe
  grant_type: password
  scope: admin
}
gdonato
  • 151
  • 1
  • 5
  • 1
    THANK YOU! I gave up on this a long time ago but today I had to complete the project. I came back here intending to post this question again and found your answer. It was exactly what I was looking for. THANK YOU! –  Oct 28 '14 at 22:35
1

You do this by passing in an extra param, and choosing the model you want to authenticate based on that param. This is similar to gdonato's answer, but scopes in doorkeeper are better used for managing which permissions are being given to the authenticated app (i.e. "Give this app permission to read X and write Y on your behalf").

Here's what I'm using

resource_owner_from_credentials do |routes|
  if params[:user_type].present?
    case params[:user_type]
    when 'user'
      u = User.find_for_database_authentication(email: params[:email])
    when 'employer'
      u = Employer.find_for_database_authentication(email: params[:email])
    when 'admin'
      u = Administrator.find_for_database_authentication(email: params[:email])
    end
  end # I don't want a default auth user_type, so no 'else' block for me
  user if user && user.valid_password?(params[:password])
end

Note that if you were to do this using scopes instead of a param that doorkeeper isn't already using for something else, you'll have to configure the scopes like:

# These are found in doorkeeper.rb, but they're commented by default.
# You would use whatever scopes you're wanting to check
default_scopes  :public
optional_scopes :write, :update

Using scope as a param to differentiate between User and Admin might work without jiggering default_scopes or optional_scopes in doorkeeper.rb, but only as a side effect of the scoping that doorkeeper expects.

jgautsch
  • 291
  • 2
  • 5