diff --git a/lib/oauth2/client.rb b/lib/oauth2/client.rb index a73e33f9..c6807a50 100644 --- a/lib/oauth2/client.rb +++ b/lib/oauth2/client.rb @@ -130,7 +130,7 @@ def request(verb, url, opts = {}) # rubocop:disable CyclomaticComplexity, Method # @param [Hash] access token options, to pass to the AccessToken object # @param [Class] class of access token for easier subclassing OAuth2::AccessToken # @return [AccessToken] the initialized AccessToken - def get_token(params, access_token_opts = {}, access_token_class = AccessToken) # rubocop:disable Metrics/AbcSize, Metrics/MethodLength + def get_token(params, access_token_opts = {}, access_token_class = AccessToken) # rubocop:disable Metrics/AbcSize, Metrics/MethodLength, Metrics/PerceivedComplexity params = authenticator.apply(params) opts = {:raise_errors => options[:raise_errors], :parse => params.delete(:parse)} headers = params.delete(:headers) || {} @@ -143,7 +143,10 @@ def get_token(params, access_token_opts = {}, access_token_class = AccessToken) end opts[:headers].merge!(headers) response = request(options[:token_method], token_url, opts) - if options[:raise_errors] && !(response.parsed.is_a?(Hash) && response.parsed['access_token']) + response_contains_token = response.parsed.is_a?(Hash) && + (response.parsed['access_token'] || response.parsed['id_token']) + + if options[:raise_errors] && !response_contains_token error = Error.new(response) raise(error) end diff --git a/spec/oauth2/strategy/auth_code_spec.rb b/spec/oauth2/strategy/auth_code_spec.rb index 63546f77..f0a9f308 100644 --- a/spec/oauth2/strategy/auth_code_spec.rb +++ b/spec/oauth2/strategy/auth_code_spec.rb @@ -8,6 +8,7 @@ let(:facebook_token) { kvform_token.gsub('_in', '') } let(:json_token) { MultiJson.encode(:expires_in => 600, :access_token => 'salmon', :refresh_token => 'trout', :extra_param => 'steve') } let(:redirect_uri) { 'http://example.com/redirect_uri' } + let(:microsoft_token) { 'id_token=jwt' } let(:client) do OAuth2::Client.new('abc', 'def', :site => 'http://api.example.com') do |builder| @@ -20,6 +21,8 @@ [200, {'Content-Type' => 'application/json'}, json_token] when 'from_facebook' [200, {'Content-Type' => 'application/x-www-form-urlencoded'}, facebook_token] + when 'from_microsoft' + [200, {'Content-Type' => 'application/x-www-form-urlencoded'}, microsoft_token] end end stub.post('/oauth/token', 'client_id' => 'abc', 'client_secret' => 'def', 'code' => 'sushi', 'grant_type' => 'authorization_code') do |env| @@ -87,6 +90,16 @@ end end + describe '#get_token' do + it "doesn't treat an OpenID Connect token with only an id_token (like from Microsoft) as invalid" do + @mode = 'from_microsoft' + client.options[:token_method] = :get + client.options[:auth_scheme] = :request_body + @access = subject.get_token(code) + expect(@access['id_token']).to eq('jwt') + end + end + %w[json formencoded from_facebook].each do |mode| [:get, :post].each do |verb| describe "#get_token (#{mode}, access_token_method=#{verb}" do