Doorkeeper: custom error message, based on conditions - resource owner password credentials

Created on 1 Nov 2013  路  5Comments  路  Source: doorkeeper-gem/doorkeeper

Is there a way to customize error response based on different conditions.

I have a mobile app and I am using resource owner password credentials flow to authenticate it.

So for authentication, I have a few conditions where a user is not authenticated, for example - when a user's state is not active in which I need to show him a message that his account is not yet active.
This may not be according to the Oauth2 specs but is there a way around it.

I followed this, https://github.com/applicake/doorkeeper/issues/299 but i can not have conditions based on this.Or if there is an existing issue related to this, would love if somebody could link me to it(Sorry I tried looking but no luck).

questiodiscussion

Most helpful comment

I have implement that by override tokens_controller

  1. config/initializes/doorkeeper.rb
Doorkeeper.configure do

  resource_owner_from_credentials do |routes|
    result = Session.authorize(params[:username], params[:password])
    # result be a hash like this { type: ok, user_id: 1111 } or { type: :password_invalid, msg: "password invalid."}
    if result[:type] == :ok
      User.find_by_id(result[:user_id]) 
    else
      params[:__auth_error] = result
      raise Doorkeeper::Errors::DoorkeeperError
    end
  end

end
  1. config/routes.rb
MyApp::Application.routes.draw do

  use_doorkeeper do
    controllers tokens: 'tokens'
  end

end
  1. app/controllers/tokens_controller.rb
class TokensController < Doorkeeper::TokensController
   def create
     response = strategy.authorize
     self.headers.merge! response.headers
     self.response_body = response.body.to_json
     self.status        = response.status
   rescue Doorkeeper::Errors::DoorkeeperError => e
     auth_error_hash = params[:__auth_error]
     if !auth_error_hash.blank?
       error_type = auth_error_hash.delete(:type)
       error_description = auth_error_hash.delete(:msg)

       error = get_error_response_from_exception e
       self.headers.merge!  error.headers
       self.response_body = { error: "invalid_grant", error_type: error_type, error_description: error_description }.merge(auth_error_hash).to_json
       self.status        = error.status
     else
       handle_token_exception e
     end
   end
end

All 5 comments

I have implement that by override tokens_controller

  1. config/initializes/doorkeeper.rb
Doorkeeper.configure do

  resource_owner_from_credentials do |routes|
    result = Session.authorize(params[:username], params[:password])
    # result be a hash like this { type: ok, user_id: 1111 } or { type: :password_invalid, msg: "password invalid."}
    if result[:type] == :ok
      User.find_by_id(result[:user_id]) 
    else
      params[:__auth_error] = result
      raise Doorkeeper::Errors::DoorkeeperError
    end
  end

end
  1. config/routes.rb
MyApp::Application.routes.draw do

  use_doorkeeper do
    controllers tokens: 'tokens'
  end

end
  1. app/controllers/tokens_controller.rb
class TokensController < Doorkeeper::TokensController
   def create
     response = strategy.authorize
     self.headers.merge! response.headers
     self.response_body = response.body.to_json
     self.status        = response.status
   rescue Doorkeeper::Errors::DoorkeeperError => e
     auth_error_hash = params[:__auth_error]
     if !auth_error_hash.blank?
       error_type = auth_error_hash.delete(:type)
       error_description = auth_error_hash.delete(:msg)

       error = get_error_response_from_exception e
       self.headers.merge!  error.headers
       self.response_body = { error: "invalid_grant", error_type: error_type, error_description: error_description }.merge(auth_error_hash).to_json
       self.status        = error.status
     else
       handle_token_exception e
     end
   end
end

and then the response.body will be:

{"error":"invalid_grant","error_type":"password_invalid","error_description":"password invalid."}

Oh thank you.. very neat.

Even though this is closed, there might be a better solution, by overriding some of Doorkeeper's methods in an own helper. This is how I do it:

module Doorkeeper
  module Helpers::Controller
    alias_method :old, :get_error_response_from_exception

    def get_error_response_from_exception(exception)
      error_name = case exception
                     when Errors::OwnError
                       :own_error
                   end
      if error_name
        OAuth::ErrorResponse.new name: error_name, state: params[:state]
      else
        old exception
      end
    end
  end

  module Errors
    class OwnError < DoorkeeperError
    end
  end
end

Put all this under lib/doorkeeper/helpers/doorkeeper_helper.rb and require it in your doorkeeper initializer. Don't forget to add an error message under the specified key in your doorkeeper locales.

Exactly what i was looking for @checkbutton. I digged into the code source and was planning to craft it but being lazy is nice as well.

Was this page helpful?
0 / 5 - 0 ratings