Search code examples
google-mapsgoogle-apigoogle-api-ruby-client

Google Maps Coordinate API client authenticates okay but returns 403 forbidden when executed


I've been following all (and sometimes conflicting) documentations I could find but nothing worked for me so I hope I get some answers by someone in the know. Many thanks in advance.

I have a trial Google Maps Coordinate account that works well in the browser. Now I'm trying to access it programmatically using google-api-ruby-client. I've set up a server-to-server certificate.

I can authenticate okay (I think) because I can get an access token. But when I call client.execute I get 403 forbidden. I am not over-quota as shown on google api console (1000/day) and I am not calling fast (less than 1/sec).

Following is what shows in irb. Of note is line 32. You can clearly see I have an access token. The results coming back after line 38 still has the access token yet access is denied.

2.0.0p195 :021 >     require 'google/api_client/client_secrets'
=> false 
2.0.0p195 :022 > 
2.0.0p195 :023 >       key = Google::APIClient::PKCS12.load_key('privatekey.p12', 'notasecret')
=> #<OpenSSL::PKey::RSA:0x007fe70667bdb8> 
2.0.0p195 :024 >     client = Google::APIClient.new
Google::APIClient - Please provide :application_name and :application_version when initializing the client
=> #<Google::APIClient:0x007fe706680340 @host="www.googleapis.com", @port=443, @discovery_path="/discovery/v1", @user_agent="google-api-ruby-client/0.6.4 Mac OS X/10.8.5", @authorization=#<Signet::OAuth2::Client:0x007fe7067df970 @authorization_uri=#<Addressable::URI:0x3ff3833ef8f8 URI:https://accounts.google.com/o/oauth2/auth>, @token_credential_uri=#<Addressable::URI:0x3ff3833ef3e4 URI:https://accounts.google.com/o/oauth2/token>, @client_id=nil, @client_secret=nil, @scope=nil, @state=nil, @code=nil, @redirect_uri=nil, @username=nil, @password=nil, @issuer=nil, @principal=nil, @expiry=60, @audience=nil, @signing_key=nil, @extension_parameters={}>, @auto_refresh_token=true, @key=nil, @user_ip=nil, @discovery_uris={}, @discovery_documents={}, @discovered_apis={}> 
2.0.0p195 :025 >     client.authorization = Signet::OAuth2::Client.new(
2.0.0p195 :026 >             :token_credential_uri => 'https://accounts.google.com/o/oauth2/token',
2.0.0p195 :027 >             :audience => 'https://accounts.google.com/o/oauth2/token',
2.0.0p195 :028 >             :scope => 'https://www.googleapis.com/auth/coordinate',
2.0.0p195 :029 >             :issuer => '759273242939-7ens86h2qti3610f29v066v9shcq1v2t@developer.gserviceaccount.com',
2.0.0p195 :030 >             :signing_key => key)
=> #<Signet::OAuth2::Client:0x007fe7080ded68 @authorization_uri=nil, @token_credential_uri=#<Addressable::URI:0x3ff38406f024 URI:https://accounts.google.com/o/oauth2/token>, @client_id=nil, @client_secret=nil, @scope=["https://www.googleapis.com/auth/coordinate"], @state=nil, @code=nil, @redirect_uri=nil, @username=nil, @password=nil, @issuer="759273242939-7ens86h2qti3610f29v066v9shcq1v2t@developer.gserviceaccount.com", @principal=nil, @expiry=60, @audience="https://accounts.google.com/o/oauth2/token", @signing_key=#<OpenSSL::PKey::RSA:0x007fe70667bdb8>, @extension_parameters={}> 
2.0.0p195 :031 > 
2.0.0p195 :032 >       client.authorization.fetch_access_token!
=> {"access_token"=>"ya29.AHES6ZQLZdWkZVDdPwLY7rasxjFYKP89GQipfM6wR-EPRdimGA6pdQ", "token_type"=>"Bearer", "expires_in"=>3600} 
2.0.0p195 :033 > 
2.0.0p195 :034 >       coordinate = client.discovered_api('coordinate')
=> #<Google::APIClient::API:0x3ff3805d7b78 ID:coordinate:v1> 
2.0.0p195 :035 > 
2.0.0p195 :036 >       results = client.execute(
2.0.0p195 :037 >             :api_method => coordinate.jobs.list,
2.0.0p195 :038 >             :parameters => {'teamId' => 'ZXJgk_kzS2iy-Z-9yvMTxw'})
=> #<Google::APIClient::Result:0x007fe700c479a0 @request=#<Google::APIClient::Request:0x007fe700c0e6c8 @parameters={"teamId"=>"ZXJgk_kzS2iy-Z-9yvMTxw"}, @headers={"User-Agent"=>"google-api-ruby-client/0.6.4 Mac OS X/10.8.5"}, @api_method=#<Google::APIClient::Method:0x3ff3805da60c ID:coordinate.jobs.list>, @authenticated=nil, @authorization=#<Signet::OAuth2::Client:0x007fe7080ded68 @authorization_uri=nil, @token_credential_uri=#<Addressable::URI:0x3ff38406f024 URI:https://accounts.google.com/o/oauth2/token>, @client_id=nil, @client_secret=nil, @scope=["https://www.googleapis.com/auth/coordinate"], @state=nil, @code=nil, @redirect_uri=nil, @username=nil, @password=nil, @issuer="759273242939-7ens86h2qti3610f29v066v9shcq1v2t@developer.gserviceaccount.com", @principal=nil, @expiry=60, @audience="https://accounts.google.com/o/oauth2/token", @signing_key=#<OpenSSL::PKey::RSA:0x007fe70667bdb8>, @extension_parameters={}, @grant_type=nil, @refresh_token=nil, @issued_at=2013-11-12 11:32:28 +0800, @access_token="ya29.AHES6ZQLZdWkZVDdPwLY7rasxjFYKP89GQipfM6wR-EPRdimGA6pdQ", @expires_in=3600>, @body="">, @response=#<Faraday::Response:0x007fe700c479f0 @env={:method=>:get, :body=>"{\n \"error\": {\n  \"errors\": [\n   {\n    \"domain\": \"global\",\n    \"reason\": \"forbidden\",\n    \"message\": \"Forbidden\"\n   }\n  ],\n  \"code\": 403,\n  \"message\": \"Forbidden\"\n }\n}\n", :url=>#<URI::HTTPS:0x007fe700c24298 URL:https://www.googleapis.com/coordinate/v1/teams/ZXJgk_kzS2iy-Z-9yvMTxw/jobs>, :request_headers=>{"User-Agent"=>"google-api-ruby-client/0.6.4 Mac OS X/10.8.5", "Authorization"=>"Bearer ya29.AHES6ZQLZdWkZVDdPwLY7rasxjFYKP89GQipfM6wR-EPRdimGA6pdQ", "Cache-Control"=>"no-store", "Content-Type"=>"application/x-www-form-urlencoded"}, :parallel_manager=>nil, :request=>{:proxy=>nil}, :ssl=>{}, :status=>403, :response_headers=>{"content-type"=>"application/json; charset=UTF-8", "date"=>"Tue, 12 Nov 2013 03:32:27 GMT", "expires"=>"Tue, 12 Nov 2013 03:32:27 GMT", "cache-control"=>"private, max-age=0", "x-content-type-options"=>"nosniff", "x-frame-options"=>"SAMEORIGIN", "x-xss-protection"=>"1; mode=block", "server"=>"GSE", "alternate-protocol"=>"443:quic", "connection"=>"close"}, :response=>#<Faraday::Response:0x007fe700c479f0 ...>}, @on_complete_callbacks=[]>> 
2.0.0p195 :039 >     
2.0.0p195 :040 >       puts results.data.to_json
{"error":{"errors":[{"domain":"global","reason":"forbidden","message":"Forbidden"}],"code":403,"message":"Forbidden"}}
=> nil 
2.0.0p195 :041 > 

Solution

  • You might be having trouble because your Service Account doesn't have a Google Maps Coordinate license. I don't know of a way to give a Service Account access to Coordinate, but I have used these 2 potential workarounds:

    1. Switch from using a Service Account to the Installed Application flow, when you script starts it will need to prompt a user who has access to the Coordinate team to login and give the application access but after this point it should be good to go.
    2. Have your service account act on behalf of a user who has Coordinate. You can enable a setting on your domain to let a service account act on behalf of users for certain scopes, this is documented here: https://developers.google.com/drive/delegation.