简体   繁体   中英

Trouble authenticating with Google Content API for Shopping

I'm trying to use OAuth2 for Server to Server Applications in conjunction with Google's Content API for Shopping using the google-api-client gem and Ruby on Rails 3.2.5. Also, I have already set up my merchant account as prescribed in the Content API documentation.

This was the best way I found to be able to:

  • create/update products in the background
  • have created products fall under my company's Google Products 'umbrella'
  • not require every user to authenticate/authorize when their token expires

Using lines 1 - 23 from this sample as a starting point, I've begun to write the following module for use in background jobs:

require 'httparty'
require 'google/api_client'

module GoogleProducts
  GOOGLE_CONFIG = YAML.load_file(File.join(Rails.root, "config", "google.yml"))[Rails.env]

  CLIENT_ID = "XXXXXXXXXXXX@developer.gserviceaccount.com"
  MERCHANT_ID = "XXXXXXX"
  SCOPE = "https://www.googleapis.com/auth/structuredcontent"

  KEY_FILE_PATH = File.join(Rails.root, "config", "my-privatekey.p12")
  KEY_FILE_PASS = "XXXXXXXXXX"

  def self.add_item(item_id)
    self.fetch_token
    xml = self.gen_item_xml(item_id)
    headers = {"Content-type" => "application/atom+xml", "Content-Length" => xml.length.to_s}
    url = "https://content.googleapis.com/content/v1/#{MERCHANT_ID}/items/products/generic?access_token=#{$gp_token}"

    response = HTTParty.post(url, :body => xml, :headers => headers).parsed_response
  end

  def self.gen_item_xml(item_id)
    #building product xml
  end

  private
  def self.fetch_token
    api_client = Google::APIClient.new(:authorization => :oauth2)
    key = Google::APIClient::PKCS12.load_key(KEY_FILE_PATH, KEY_FILE_PASS)
    asserter = Google::APIClient::JWTAsserter.new(CLIENT_ID, SCOPE, key)

    begin
      api_client.authorization = asserter.authorize

      #todo - store in something other than a global
      $gp_token = api_client.authorization.access_token
    rescue Signet::AuthorizationError => e
      puts e.message
    ensure
      return $gp_token
    end
  end
end

Everything seemingly works fine - the authentication, the handling of the auth token - until I attempt to actually add an item, which I get the following when I do:

<errors xmlns='http://schemas.google.com/g/2005'>
  <error>
    <domain>GData</domain>
    <code>ServiceForbiddenException</code>
    <internalReason>Could not find authenticated customer</internalReason>
  </error>
</errors>

Any ideas?

After much anguish and mental toil, I've finally solved my issue!

Since I am using OAuth 2 Server to Server authentication the suggestion hjblok gave didn't apply (thanks for giving it a shot, though!).

I simply added the email address that was associated with my Service Account key from the Google API Console (eg XXXXXXXXXXXX@developer.gserviceaccount.com ) to my Google Merchant account ( Settings > Users on the merchant admin page), and it worked.

If there's any clarification needed, please feel free to comment!

The Google Content API documentation says you need to set it up in the Settings page of the Google Merchant Center:

https://developers.google.com/shopping-content/getting-started/usingapi-products

EDIT rewrote the answer after diving into the Google's API documentation

Did you already try to use Google's OAuth 2.0 playground ? I was able to successfully access https://content.googleapis.com/content/v1/#{MERCHANT_ID}/items/products/generic .

  1. In "Step 1" I've chosen the "Content API for Shopping" and then authorized the API with my account.
  2. Then in "Step 2" I've "exchanged authorization code for tokens", which results in a "refresh token" and an "access token".
  3. Then in "Step 3" I've invoked a GET request to https://content.googleapis.com/content/v1/1234567/items/products/generic . Because 1234567 is not a valid MERCHANT_ID it returns an Error. But the Error Messages contains a MERCHANT_ID which actually belongs to your account.
  4. I repeated "Step 3" but now with the correct MERCHANT_ID . Which returns a HTTP/1.1 200 OK with the requested items in the body.

Furthermore I'm not sure, but doesn't Google API expect an Authorization header to be present with the access_token ( $gp_token )? Within the OAuth 2.0 playground this Authorization header is used to sent the access_token .

I also found the Structured Content API demo page (https://google-content-api-tools.appspot.com/demo/demo.html), which is more specific to the Content API for Shopping.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM