diff --git a/lib/xero_gateway/http.rb b/lib/xero_gateway/http.rb index fb25b75c..a580ecdf 100644 --- a/lib/xero_gateway/http.rb +++ b/lib/xero_gateway/http.rb @@ -99,7 +99,7 @@ def handle_oauth_error!(response) # a second. case (error_details["oauth_problem"].first) when "token_expired" then raise OAuth::TokenExpired.new(description) - when "consumer_key_unknown" then raise OAuth::TokenInvalid.new(description) + when "consumer_key_unknown" then raise OAuth::ConsumerConfigError.new(description) when "token_rejected" then raise OAuth::TokenInvalid.new(description) when "rate limit exceeded" then raise OAuth::RateLimitExceeded.new(description) else diff --git a/lib/xero_gateway/oauth.rb b/lib/xero_gateway/oauth.rb index 35f18b89..daf89d67 100644 --- a/lib/xero_gateway/oauth.rb +++ b/lib/xero_gateway/oauth.rb @@ -11,6 +11,7 @@ class OAuth class TokenExpired < StandardError; end class TokenInvalid < StandardError; end class RateLimitExceeded < StandardError; end + class ConsumerConfigError < StandardError; end class UnknownError < StandardError; end unless defined? XERO_CONSUMER_OPTIONS @@ -80,10 +81,26 @@ def renew_access_token(access_token = nil, access_secret = nil, session_handle = update_attributes_from_token(access_token) rescue ::OAuth::Unauthorized => e - # If the original access token is for some reason invalid an OAuth::Unauthorized could be raised. - # In this case raise a XeroGateway::OAuth::TokenInvalid which can be captured by the caller. In this - # situation the end user will need to re-authorize the application via the request token authorization URL - raise XeroGateway::OAuth::TokenInvalid.new(e.message) + #note that e.request is a Net::HTTP _response_ + error_details = CGI.parse(e.request.body.strip) + + #Xero will respond with 401 in a variety of circumstances, which will surface as OAuth::Unauthorized errors, + # but may have different remedies (user needs to re-authorize, developer must fix configuration for client, etc.). + #Cases are distinguishable by `oauth_problem` response body parameter - message is oauth_problem_advice to be + # consistent with XeroGateway::Http#handle_oauth_error! + #https://developer.xero.com/documentation/auth-and-limits/oauth-issues + problem = error_details['oauth_problem'].first + description = error_details["oauth_problem_advice"].first + description = "No description found: #{e.request.plain_body}" if description.blank? + + if problem == 'consumer_key_unknown' + raise XeroGateway::OAuth::ConsumerConfigError.new(description) + else + # If the original access token is for some reason invalid an OAuth::Unauthorized could be raised. + # In this case raise a XeroGateway::OAuth::TokenInvalid which can be captured by the caller. In this + # situation the end user will need to re-authorize the application via the request token authorization URL + raise XeroGateway::OAuth::TokenInvalid.new(description) + end end def get(path, headers = {}) diff --git a/test/unit/gateway_test.rb b/test/unit/gateway_test.rb index 287b35da..e158f872 100644 --- a/test/unit/gateway_test.rb +++ b/test/unit/gateway_test.rb @@ -176,7 +176,7 @@ def setup should "handle invalid consumer key" do XeroGateway::OAuth.any_instance.stubs(:get).returns(stub(:plain_body => get_file_as_string("invalid_consumer_key"), :code => "401")) - assert_raises XeroGateway::OAuth::TokenInvalid do + assert_raises XeroGateway::OAuth::ConsumerConfigError do @gateway.get_accounts end end