I'm receiving this error trying to authenticate with the Adwords API using a service account and JWT with the Ruby API library.
I am copying the example provided, but it just doesn't seem to work.
/home/michael/.rvm/gems/ruby-2.1.2/gems/signet-0.5.1/lib/signet/oauth_2/client.rb:941:in `fetch_access_token': Authorization failed. Server message: (Signet::AuthorizationError)
{
"error" : "invalid_grant"
}
adwords_api.yml
---
# This is an example configuration file for the AdWords API client library.
# Please fill in the required fields, and copy it over to your home directory.
:authentication:
# Authentication method, methods currently supported: OAUTH2, OAUTH2_JWT.
:method: OAUTH2_JWT
# Auth parameters for OAUTH2_JWT method. See:
# https://developers.google.com/accounts/docs/OAuth2ServiceAccount
:oauth2_issuer: 43242...apps.googleusercontent.com
:oauth2_secret: 'notasecret'
# You can provide path to a file with 'oauth2_keyfile' or the key itself with
# 'oauth2_key' option.
:oauth2_keyfile: /home/.../google-api-key.p12
# To impersonate a user set prn to an email address.
:oauth2_prn: my#email.com
# Other parameters.
:developer_token: ua...w
:client_customer_id: 123-123-1234
:user_agent: test-agent
:service:
# Only production environment is available now, see: http://goo.gl/Plu3o
:environment: PRODUCTION
:connection:
# Enable to request all responses to be compressed.
:enable_gzip: false
# If your proxy connection requires authentication, make sure to include it in
# the URL, e.g.: http://user:password#proxy_hostname:8080
# :proxy: INSERT_PROXY_HERE
:library:
:log_level: INFO
test.rb
#!/usr/bin/env ruby
require 'adwords_api'
def use_oauth2_jwt()
adwords = AdwordsApi::Api.new
adwords.authorize()
campaign_srv = adwords.service(:CampaignService, API_VERSION)
selector = {
:fields => ['Id', 'Name', 'Status'],
:ordering => [
{:field => 'Name', :sort_order => 'ASCENDING'}
]
}
response = campaign_srv.get(selector)
if response and response[:entries]
campaigns = response[:entries]
campaigns.each do |campaign|
puts "Campaign ID %d, name '%s' and status '%s'" %
[campaign[:id], campaign[:name], campaign[:status]]
end
else
puts 'No campaigns were found.'
end
end
if __FILE__ == $0
API_VERSION = :v201409
begin
use_oauth2_jwt()
# HTTP errors.
rescue AdsCommon::Errors::HttpError => e
puts "HTTP Error: %s" % e
# API errors.
rescue AdwordsApi::Errors::ApiException => e
puts "Message: %s" % e.message
puts 'Errors:'
e.errors.each_with_index do |error, index|
puts "\tError [%d]:" % (index + 1)
error.each do |field, value|
puts "\t\t%s: %s" % [field, value]
end
end
end
end
This is going to be difficult to answer definitively as it's authorisation based so the error message is a glorified "not authorised" message.
All I can really do is suggest a few things to check (acknowledging you've probably went through these already):
Your developer token is definately showing as 'Approved'? (you can check this in the client centre - through the setting cog then account then adwords api centre)
You have registered an application through Google Developer Console
You (or the owner of the account you are trying to access) have authorised your application - probably by following this guide and definately seeing one of these things at somepoint:
If you have checked all of these then the only other thing I can suggest is a post to the official forum where they tend to be helpful and often take authorisation issues 'offline' to have a look at the actual soap requests etc. (I have found this much quicker and easier than trying to wade through the levels of AdWords 'support')
Good luck!
After several more hours of fiddling, I finally got it working by setting the oauth2_prn to the primary email on the MCC and Google Apps for Business account.
Related
I am using the DocuSign_eSign ruby gem version 1.0.2 because version 2.0.0 does not handle JWT auth. The eg-01-ruby-jwt example provided by DocuSign uses v1.0.2 as well, so I just pinned this version in my Gemfile.
I am getting the following error when I attempt to make a call using the DocuSign_eSign::EnvelopesApi.new#create_envelope method:
docusign_esign-1.0.2/lib/docusign_esign/api_client.rb:66:in `call_api': Bad Request (DocuSign_eSign::ApiError)
For good measure, I walked through the code line by line to get a better idea of what was happening, and I ended up with this error:
irb(main):101:0> response.code
=> 401
irb(main):103:0> response.body
=> "{\r\n \"errorCode\": \"PARTNER_AUTHENTICATION_FAILED\",\r\n \"message\": \"The specified Integrator Key was not found or is disabled. An Integrator key was not specified.\"\r\n}"
irb(main):104:0> response.status_message
=> "Unauthorized"
Here is the ruby code (minus logging/error handling) from my DocuSignWebClient where I trigger the call (send_envelope). This is where the auth happens:
TOKEN_REPLACEMENT_IN_SECONDS = 10.minutes.seconds
TOKEN_EXPIRATION_IN_SECONDS = 1.hour.seconds
def initialize(options = {})
#docusign_config = Padrino.config.docusign
#api_client = DocuSignWebClient.setup_api_client
#s3_client = options[:s3_client] || Aws::S3::Client.new(region: Padrino.config.aws.region)
#token_expire_in = options[:token_expire_in] || 0
#account_id = options[:account_id]
end
def self.setup_api_client
configuration = DocuSign_eSign::Configuration.new
DocuSign_eSign::ApiClient.new(configuration)
end
def send_envelope(details)
authorize
envelope = DocuSign::EnvelopeBuilder.new(details, #s3_client).build_envelope
sender = DocuSign::EnvelopeSender.new(#api_client, #account_id)
response = sender.send_envelope(envelope)
update_document_status(details, response)
end
def authorize
check_token
#account_id ||= update_account_id
end
def check_token
if no_token? || token_near_expiration?
update_token
end
end
def no_token?
!#api_client.default_headers['Authorization']
end
def token_near_expiration?
now = Time.now.to_f
(now + TOKEN_REPLACEMENT_IN_SECONDS) > #token_expire_in
end
def update_token
configure_jwt_authorization_flow
#token_expire_in = Time.now.to_f + TOKEN_EXPIRATION_IN_SECONDS
end
def configure_jwt_authorization_flow
#api_client.configure_jwt_authorization_flow(#docusign_config[:private_key_file],
#docusign_config[:auth_server],
#docusign_config[:integrator_key],
#docusign_config[:user_id],
TOKEN_EXPIRATION_IN_SECONDS)
end
def update_account_id
account = fetch_account_info
#api_client.config.host = account[:base_uri]
account[:account_id]
end
def fetch_account_info
response = DocuSignResponse.new(#api_client.call_api('GET', "https://#{#docusign_config[:auth_server]}/oauth/userinfo", return_type: 'Object'))
if response.ok?
response.data[:accounts].detect { |acct| acct[:is_default] }
end
end
I am getting a token back from DocuSign after I go through the authorization flow, but it says that the token is not valid once I try to use it.
irb(main):033:0> account_id = client.authorize
=> "386...a24"
irb(main):036:0> client.api_client
=> #<DocuSign_eSign::ApiClient:0x00007ff6d243c8c8 #config=#<DocuSign_eSign::Configuration:0x00007ff6d243d2f0 #scheme="https", #host="demo.docusign.net", #base_path="/restapi", #api_key={}, #api_key_prefix={}, #timeout=0, #verify_ssl=true, #verify_ssl_host=true, #params_encoding=nil, #cert_file=nil, #key_file=nil, #debugging=false, #inject_format=false, #force_ending_format=false, #logger=#<Logger:0x00007ff6d243d110 #level=0, #progname=nil, #default_formatter=#<Logger::Formatter:0x00007ff6d243d098 #datetime_format=nil>, #formatter=nil, #logdev=#<Logger::LogDevice:0x00007ff6d243cfa8 #shift_period_suffix=nil, #shift_size=nil, #shift_age=nil, #filename=nil, #dev=#<IO:<STDOUT>>, #mon_mutex=#<Thread::Mutex:0x00007ff6d243c8f0>, #mon_mutex_owner_object_id=70349033170900, #mon_owner=nil, #mon_count=0>>>, #user_agent="Swagger-Codegen/1.0.2/ruby", #default_headers={"Content-Type"=>"application/json", "User-Agent"=>"Swagger-Codegen/1.0.2/ruby", "Authorization"=>"Bearer eyJ0eXAiOiJNVCIsImFsZyI6IlJTMjU2Iiwia2lkIjoiNjgxODVmZjEtNGU1MS00Y2U5LWFmMWMtNjg5ODEyMjAzMzE3In0.AQkAAAABAAUABwAACzCudSXXSAgAAHP0D34l10gCABIJ3tlGgoJMvWi9_zzeFocVAAEAAAAYAAEAAAAFAAAADQAkAAAAZTVjOTIwMTItMWI0ZC00ZTgzLTgzNjYtNjgzNDQ0NjQyNjc0IwAkAAAAZTVjOTIwMTItMWI0ZC00ZTgzLTgzNjYtNjgzNDQ0NjQyNjc0EgABAAAABgAAAGp3dF9icg.yt_0QtjwAcL1dosfVuaNoKoM3Yzq9DK4MUf6lx3Sp5EYy0OdeSaKt6TgsAujUNQQoQH4e_IZFGtVXxBjFXzP2hh9EB2nsdwKAzi5EZJcOIp1wEfzKjEllUnOXOkEoUwcmHHCSN1j4LfNF8olRTDJnaSDB9A5TbumLURC_-FkttxHitFVpt39Fvl85VtSlIsQxU544SRjeJGJMl_BDwRmu0JrUSawc5LSUF9ET9SVTBGEjS_vZMz92hdiFM2x4qZqupeSXLrQ92bhzjEXHOH7kmKbE-iKDTH_TOln0rhhqLXq25yOTBJ_yUWqhvYaxpct9GRuPo6IIZCDDv0Of7k-xQ"}>
Does anything in that API instance look wrong? I can't figure out why my token is not working.
UPDATE: I re-attempted the same flow with a token using the OAuth Token Generator and that token also fails with the same error. Additionaly, I am able to send a token using the eg-01-ruby-jwt example code with the SAME EXACT inputs when calling DocuSign_eSign::ApiClient#configure_jwt_authorization_flow. The Envelopes API takes the API client and the account ID, which are identical upon inspection between the example code and my code (besides the auth token).
Try to use the token generator (https://developers.docusign.com/oauth-token-generator) and see if that token works for you. That would isolate the issue to obtaining the token.
Make sure in the sandbox admin, you configured your IK correctly, and that you use the exact same one.
You need an RSA key generated and make sure to use it for JWT.
Make sure you point to account-d.docusign.com and not account.docusign.com (so you use our developer sandbox and not production)
After a day trying, testing, googling ... I ask for some help
I try to use Omniauth and Google Calendar. OmniAuth is working like a charm but I just can't link it with Google API
I think I read almost everything, I still get this error message :
dailyLimitExceededUnreg: Daily Limit for Unauthenticated Use Exceeded.
Continued use requires sign up.
It means that my calls are not properly 'connected' to my auth, which seems to be valid. My tokens are in databases but I this point I would like to login / identify / call and have something else that an error message.
client_id = Google::Auth::ClientId.from_file('.....googleusercontent.com.json')
scopes = ['userinfo.email,calendar']
token_store = Google::Auth::MyTokenStore.new()
authorizer = Google::Auth::WebUserAuthorizer.new(
client_id,
scopes,
token_store,
'http://localhost:3000'
)
# credentials = Google::Auth::UserAuthorizer.new( . # Anotheir test
# client_id,
# scopes,
# token_store,
# 'http://localhost:3000'
# )
#
# authorizer = credentials.get_credentials_from_code(
# GoogleUser.find(session[:user_id]) # I tested token ... notking worked
# )
calendar = Google::Apis::CalendarV3::CalendarService.new
calendar.authorization = authorizer
calendar_id = 'primary'
#result = calendar.list_events(calendar_id,
max_results: 10,
single_events: true,
order_by: 'startTime',
time_min: Time.now.iso8601)
and my token storage , I don't understand why but never called
class MyTokenStore
class << self
attr_accessor :default
end
def load(_id)
puts "********** load ************"
return GoogleUser.find(session[:user_id]).access_token
end
def store(_id, _token)
puts "********** store ************"
#user.access_token = _token
end
def delete(_id)
puts "********** delete ************"
#user.access_token = nil
end
end
end
end
For future readers : I took a different technic, after reading an excellent article here : http://gmile.me/simple-google-auth/
I followed it and use signet, it is working like a charm
Nobody has encountered this?
I can get the email message object (Google::Apis::GmailV1::Message) but other Message attributes just returns Nil. Only id, thread_id seems to be returned.
SCOPE = Google::Apis::GmailV1::AUTH_GMAIL_MODIFY
service = Google::Apis::GmailV1::GmailService.new
service.client_options.application_name = APPLICATION_NAME
service.authorization = authorize
user_msgs = service.list_user_messages('me',
{:include_spam_trash => false, :label_ids => ['INBOX'], :q => "is:unread"})
user_msgs.messages.each do |msg|
puts "CLASS: #{msg.class}" # Google::Apis::GmailV1::Message
puts "MESSAGE ID: #{msg.id}" # WORKS I get the email ID
msg_part = msg.payload
puts "MSGPART: #{msg_part.class}" # NIL !!!, All other attributes are also NIL
end
So basically I do get the email with the correct ID, but that's about it, all methods or attributes of the GmailV1::Message class is Nil. I also tried changing the SCOPE to MODIFY and same result.
Attributes that just returns Nil:
internal_date label_ids payload raw size_estimate snippet
Also noticed that github project linked in their documentation opens a 404 page on some.
Might be due to Google now forcing developers to have publicly available apps reviewed first: https://developers.google.com/gmail/api/auth/about-auth (see the notification in the blue box with the star)
I am new to dashing and I have managed to work a lot out using the internet, however I am now at a loss as to why my widget doesn't update to the new search_term when I change it in the twitter.rb file?
I am using the default twitter.rb file with a couple of amendments. Firstly I have included my Tokens and authorisation keys from twitter.com and secondly, I have just added an extra line to receive more info when something fails in the twitter::error statement.
This is my current code (minus the keys & tokens)
search_term = URI::encode('#weather')
SCHEDULER.every '2m', :first_in => 0 do |job|
begin
tweets = twitter.search("#{search_term}")
if tweets
tweets = tweets.map do |tweet|
{ name: tweet.user.name, body: tweet.text, avatar: tweet.user.profile_image_url_https }
end
send_event('twitter_mentions', comments: tweets)
end
rescue Twitter::Error => e
puts "Twitter Error: #{e}"
puts "\e[33mFor the twitter widget to work, you need to put in your twitter API keys in the jobs/twitter.rb file.\e[0m"
end
end
I have restarted Dashing; I have even rebooted the box it is on, but all to no avail. I am a total loss.
Any help would be greatly appreciated.
I'm trying to integrate our app with MailChimp, so that new users get added to our mailing list and new paid subscribers get updated on the mailing list as paid subscribers (we have a MERGE VARS for that). In order to test that the list is updating properly when the customer pays for a subscription, I'm trying to run the code with the test server for Stripe. (I inherited the code after we had tested it, so I haven't done this before.)
I'm running into an undefined method error, and I can't figure out where it's coming from, since it is working just fine on the live site, and I haven't changed that part of the code.
in the initializer file stripe.rb, I changed Stripe.api_key
="the live secret key" to the test secret key, just subbing in the other key.
I did the same in our layout/application.html.erb file (where we put the initial call to Stripe per Stripe's instructions), swapping out the public live key for the public test key.
In the account_controller processing method (which is called for payment processing on the Stripe token and updating our server with the type of subscription.):
def processing
begin
if params[:coupon][0] != "_"
#coupon = params[:coupon]
else
#coupon = nil
end
customer = Stripe::Customer.create(
:email => current_user.email,
:card => params[:stripeToken],
:plan => params[:plan],
:coupon => #coupon
)
current_user.subscription = params[:plan]
current_user.stripe_id = customer.id
current_user.canceled = false
current_user.save!
rescue Stripe::CardError => e
flash[:error] = e.message
end
#only this code is new, from here:
#for gibbon updating subscription status
gb=Gibbon::API.new
email=current_user.email
subscription=user.subscription
updated_date=user.updated_at.strftime('%B %d, %Y')
gb.lists.subscribe({:id => "our list id", :email => {:email => "#{email}"}, :merge_vars => {:SUB => "test", :UPDATE => "#{updated_date}"}, :update_existing=>true , :double_optin => false, :send_welcome=> false})
#to here is new code
current_user
respond_to do |format|
format.html { redirect_to account_confirmation_path }
end
end
I'm getting a "NoMethodError in AccountController#processing
undefined method 'canceled=' for #User:an-id-here" (note the #User: an id here is in pointy brackets, but those aren't showing up here.)
error. This code works on the live site, so that makes me think it must be something I've done here. Canceled is a column on our User model, which is a boolean indicating whether they've canceled. It is not set as attr_accesible or attr_accessor, but as I said, that code hasn't changed and works on the live site.
I'm not sure what the problem is and I feel like I don't have enough information to start figuring it out. The server is only recording the same error message as shows up in the browser. (Oh, and I'm running the test code only on my local server, not the live server).
What might be causing the undefined method error? I'm not seeing anything in the code I changed that should do it.