I'm trying to use the PayPal Adaptive Payments Payment API. I am trying to test the API with my own email address, but I get an error specifying the sender by email. I'm wondering how to determine my own account ID to try that way?
I'm referring to the account id here: https://developer.paypal.com/docs/classic/api/adaptive-payments/PaymentDetails_API_Operation/
I get the error: "The email address smithd98#gmail.com is invalid. It may not be registered in PayPal's system yet" when trying to pay by my email. When I log in with PayPal my email address is correct. My account is verified with a bank account, credit card, and debit card connected.
Here is my code:
require 'paypal-sdk-adaptivepayments'
PayPal::SDK.configure(
:mode => "sandbox", # Set "live" for production
:app_id => "HIDDEN",
:username => "HIDDEN",
:password => "HIDDEN",
:signature => "HIDDEN" )
#api = PayPal::SDK::AdaptivePayments.new
# Build request object
#pay = #api.build_pay({
:actionType => "PAY",
:cancelUrl => "http://localhost:3000/samples/adaptive_payments/pay",
:currencyCode => "USD",
:feesPayer => "SENDER",
:ipnNotificationUrl => "http://localhost:3000/samples/adaptive_payments/ipn_notify",
:receiverList => {
:receiver => [{
:amount => 1.0,
:email => "smithd98#gmail.com" }] },
:returnUrl => "http://localhost:3000/samples/adaptive_payments/pay" })
##pay.sender.email = "smithd98#gmail.com"
#pay.sender.accountId = 23434
# Make API call & get response
puts #pay.inspect
#response = #api.pay(#pay)
# Access response
if #response.success?
puts 'responsepayKey'
#response.payKey
puts 'url to complete payment'
#api.payment_url(#response) # Url to complete payment
else
puts 'error'
puts #response.error[0].message
puts #response.error[1].parameter.value
end
You can get it via the API using GetPalDetails. You can get it manually in your PayPal profile. Go to the Business Info section and you'll see a Merchant Account ID.
On another note, I see that you're using localhost in your return and cancel URL's, as well as IPN. This isn't going to work. Remember, it's PayPal's server that will be hitting that address. If they hit localhost, they're just hitting their own server, which isn't going to do what you want, of course.
If you want to test all of this with your local test server you'll need to use your IP address or setup some DNS and a domain of some sort. I personally like to follow PayPal's lead and setup a sandbox.domain.com as a test server for any site I'm working on.
David,
To get the Account ID of your test accounts.
Login into your sandbox paypal account at https://www.sandbox.paypal.com/
Click on the "Profile" tab on the top menu
You will see your Account ID for that account beside "Merchant account ID"
It's the same exact process for a real account but instead login into your real paypal account.
Related
I'm sure that this is a simple error, but I'm interested in writing a program that collects information on all of my github repositories. While this seems simple enough to do with Octokit, I've run into issues associated with authenticating my session.
client = Octokit::Client.new \
:login => 'MY_USER_NAME',
:password => 'MY_PASSWORD'
puts client
user = client.user("MY_USER_NAME", :headers => { "PERSONAL_ACCESS_TOKEN_NAME" => "TOKEN" })
puts user
Unfortunately this results in the following:
GET https://api.github.com/users/mccoleman75225: 401 - Must specify two-factor authentication OTP code. // See: https://developer.github.com/v3/auth#working-with-two-factor-authentication (Octokit::OneTimePasswordRequired)
How does someone go about authenticating their session?
As of January 2022, you can create a PAT (Personal Access Token) in your GitHub Developer Settings and use that to connect through the Octokit client like so:
client = Octokit::Client.new(:access_token => "<Your Personal Access Token>")
user = client.user
user.login
# => "monacat"
Here's a step-by-step guide on how to create a PAT. Try to select the correct permissions when creating your token or you'll get back a 403 error with a message explaining the missing scope. You can always go back and edit your scopes later though.
Sources:
Octokit.rb — Authentication
GitHub API Authentication - Personal Access Tokens
Looks like you have 2 Factor Authentication enabled on your account so you'll need to add your 2FA token:
client = Octokit::Client.new \
:login => 'defunkt',
:password => 'c0d3b4ssssss!'
client.create_authorization(:scopes => ["user"], :note => "Name of token",
:headers => { "X-GitHub-OTP" => "<your 2FA token>" })
# => <your new oauth token>
See documentation
I have a Ruby web app that sends email via Mailgun.
My Mailgun account & gem are properly set up and I can send emails manually (via curl, for instance).
The API key and the API base URL (https sandbox domain) are stored in environment variables.
When I attempt to send emails from the app like this:
def initialize(mailer: nil)
#mailer = mailer || Mailgun::Client.new(ENV['MAILGUN_API_KEY'])
end
then:
def call(user)
mailer.send_message(ENV['MAILGUN_SANDBOX'], {from: '...',
to: user.email,
subject: '...',
text: "..."})
end
When I run the app with Sinatra via localhost:xxxx, I get a Mailgun::CommunicationError at /.../... 301 Moved Permanently: ... nginx pointing to this line:
mailer.send_message(ENV['MAILGUN_SANDBOX'], ...
Any idea why that happens? I've researched the issue for hours but couldn't find a clue on what to do next.
Thanks!
I ran into this same issue. If you have already fixed this then hopefully this can help someone else.
I switched over to message builder for ease of use and being able to render my html but I'm pretty sure it will still send with the format you have setup with :text
When I switched over to the proper domain in the .env file I believe it solved my issue. You'll need 2 different domains to use Mailgun. The first is the full domain for your sandbox. ENV['MAILGUN_DOMAIN'] it is the sandbox domain with the full https://api.mailgun.net/v3/sandboxXXXXxxxXXXXXX.mailgun.org to send most of the mail formats.
You'll also need the last half of the full domain to send messages. That's just the sandboxXXXXxxxXXXXXX.mailgun.org which is passed into the MessageBuilder or other message .send_message method. When I had them mixed up or both the same I kept on getting this error. When I switched over to separate the two in my development.rb and some_mailer.rb is when I could send the mail without a problem.
Below is my file setup, for reference. I'm pretty new to all of this but this is how I'm setup and it's working for me so hopefully it helps.
# .env
MAILGUN_DOMAIN='https://api.mailgun.net/v3/sandboxXXXXxxxXXXXXX.mailgun.org'
MAILGUN_SEND_DOMAIN='sandboxXXXXxxxXXXXXX.mailgun.org'
# development.rb
ActionMailer::Base.smtp_settings = {
:authentication => :plain,
:address => "smtp.mailgun.org",
:port => 587,
:domain => "ENV['MAILGUN_DOMAIN']",
:user_name => "ENV['MAILGUN_USERNAME']",
:password => "ENV['MAILGUN_PASSWORD']"
}
# some_mailer.rb
def some_mail_notification(user)
#user = user
mg_client = Mailgun::Client.new ENV['MAILGUN_KEY']
mb_obj = Mailgun::MessageBuilder.new
mb_obj.from "email#testing.com", {'first' => 'Customer', 'last' => 'Support'}
mb_obj.add_recipient :to, #user.email, { 'first' => #user.first_name, 'last' => #user.last_name }
mb_obj.subject "Your Recent Purchase on Some Site"
mb_obj.body_html ("#{render 'some_mail_notification.html.erb'}")
mg_client.send_message("sandboxXXXXxxxXXXXXX.mailgun.org", mb_obj)
end
I left the send_message above to the sandbox domain but you can set that as an environment variable in the .env file.
I'm having some trouble getting the sample code for instantiating a Drive Service Account working. I've set up the service account in the API console as directed and included the scope for the 'https://www.googleapis.com/auth/drive', but running this generates the following error: "Authorization failed. Server message: (Signet::AuthorizationError)".
Oddly, if I omit the user_email address it doesn't generate an error.
My objective is to be able to do an audit on all the files stored on the organization's Drive, and it's my understanding that using a service account would be the way to get a listing of all the files stored.
Have I missed some special setting on the server side for this?
require 'google/api_client'
## Email of the Service Account #
SERVICE_ACCOUNT_EMAIL = '<service account email>#developer.gserviceaccount.com'
## Path to the Service Account's Private Key file #
SERVICE_ACCOUNT_PKCS12_FILE_PATH = '<private key file>-privatekey.p12'
def build_client(user_email)
key = Google::APIClient::PKCS12.load_key(SERVICE_ACCOUNT_PKCS12_FILE_PATH, 'notasecret')
asserter = Google::APIClient::JWTAsserter.new(SERVICE_ACCOUNT_EMAIL, 'https://www.googleapis.com/auth/drive', key)
client = Google::APIClient.new
client.authorization = asserter.authorize(user_email)
return client
end
client = build_client("<users email address>")
This looks to me like you are using an older example. I think that's how you used to do it about a year ago. Back in late 2012 that method of setting up the app was deprecated because Signet was updated to handle all aspects of the OAuth2 setup.
Here is the code I generally use to create a service account. You can tweak it to fit into your method.
client.authorization = Signet::OAuth2::Client.new(
:token_credential_uri => 'https://accounts.google.com/o/oauth2/token',
:audience => 'https://accounts.google.com/o/oauth2/token',
:scope => "https://www.googleapis.com/auth/drive",
:issuer => "<service account email>#developer.gserviceaccount.com",
:signing_key => Google::APIClient::KeyUtils.load_from_pkcs12("<private key file>-privatekey.p12", "notasecret"),
:person => "<users email address>")
client.authorization.fetch_access_token!
If you are still having issues let me know and I'll see if I can help.
Using version 0.9.13 of google-api-client, I succeeded in using the following slight adaptation of Woodward's answer (note the absence of the person parameter):
def service_account_authorization(credentials_file, scope)
credentials = JSON.parse(File.open(credentials_file, 'rb').read)
authorization = Signet::OAuth2::Client.new(
:token_credential_uri => 'https://accounts.google.com/o/oauth2/token',
:audience => 'https://accounts.google.com/o/oauth2/token',
:scope => scope,
:issuer => credentials['client_id'],
:signing_key => OpenSSL::PKey::RSA.new(credentials['private_key'], nil),
)
authorization.fetch_access_token!
authorization
end
This snippet takes a file as it was downloaded from Google Cloud Console for a service account and returns an auth object that can be fed to Google::Apis::*Service.authorization.
Thanks James!
I have worked with service account+Drive+file permissions using Java. In order to use permissions for a particular user, I had to allow certain scope. The only thing I can guess about your issue is that you might have missed the Delegation part
I've been reading the docs for the Google Calendar API and the google-api-ruby-client library, but I'm having a lot of trouble understanding them.
I have a Rails application that has a front end that lets users create objects called Events, and it saves them in a database on my server. What I would like is, after these Events are saved in the database, I want to call the Google Calendar API to create an event on a Google Calendar (that the server created, and only the server has access to modify that calendar).
I'm having lots of issues figuring out how to authenticate with the API using the ruby library. It doesn't make sense for me to use OAuth2 because I don't need to authorize anything with the user because I'm not interested in their data. I looked into Service Accounts (http://code.google.com/p/google-api-ruby-client/wiki/ServiceAccounts), but it looks like Google Calendars is not supported by Service Accounts.
Anyone have any ideas? This is the code I was experimenting with (using Service Accounts):
#client = Google::APIClient.new(:key => 'my_api_key')
path_to_key_file = '/somepath/aaaaaa-privatekey.p12'
passphrase = 'my_pass_phrase'
key = Google::APIClient::PKCS12.load_key(path_to_key_file, passphrase)
asserter = Google::APIClient::JWTAsserter.new(
'blah_blah#developer.gserviceaccount.com',
'https://www.googleapis.com/auth/calendar',
key)
# To request an access token, call authorize:
#client.authorization = asserter.authorize()
calendar = #client.discovered_api('calendar', 'v3')
event = {
'summary' => 'Appointment',
'location' => 'Somewhere',
'start' => {
'dateTime' => '2012-06-03T10:00:00.000-07:00'
},
'end' => {
'dateTime' => '2012-06-03T10:25:00.000-07:00'
},
'attendees' => [
{
'email' => 'attendeeEmail'
},
#...
]
}
result = #client.execute!(:api_method => calendar.events.insert,
:parameters => {'calendarId' => 'primary'},
:body => JSON.dump(event),
:headers => {'Content-Type' => 'application/json'})
Then of course I get this error message: Google::APIClient::ClientError (The user must be signed up for Google Calendar.) because the Service Account does not support Google Calendars.
I think you'll still need a real google user to host the calendar instance. But once you've got the calendar created under your identity, you can share it with the service account. In the sharing settings for the calendar, just use the email address of the service account (my service account ends with #developer.gserviceaccount.com). With the right sharing permissions, your service account can create/alter the event info, and not mess with your specific identity. From there, you can share the calendar with more people (or public) for their consumption of the mirrored events.
The other hitch I've run into is that it seems you can only authorize() the service account once per expiration period. You'll have to save the token you get and reuse it for the next hour, and then fetch a new one.
I don't know anything about Ruby. But it seems like understanding the underlying REST queries would help debug your problem. I've documented them here: http://www.tqis.com/eloquency/googlecalendar.htm
I was having trouble with this too and finally got a handle on it. The bottom line is that Google Calendar API v3 requires OAuth and you need to setup an App/Project through the Google Developer Console and then request OAuth permission on the target Google account. Once authorization is granted, you'll want to save the refresh token and use it on subsequent calls to get new access tokens (which expire!). I wrote a detailed blog post about this here: http://www.geekytidbits.com/google-calendar-api-from-ruby/ and this is my example script that should hopefully help you understand the flow:
#gem install 'google-api-client'
require 'google/api_client'
#Setup auth client
client_secrets = Google::APIClient::ClientSecrets.load #client_secrets.json must be present in current directory!
auth_client = client_secrets.to_authorization
auth_client.update!(
:scope => 'https://www.googleapis.com/auth/calendar',
:access_type => "offline", #will make refresh_token available
:approval_prompt =>'force',
:redirect_uri => 'http://www.myauthorizedredirecturl.com'
)
refresh_token_available = File.exist?('refresh_token.txt')
if !refresh_token_available
#OAuth URL - this is the url that will prompt a Google Account owner to give access to this app.
puts "Navigate browser to: '#{auth_client.authorization_uri.to_s}' and copy/paste auth code after redirect."
#Once the authorization_uri (above) is followed and authorization is given, a redirect will be made
#to http://www.myauthorizedredirecturl.com (defined above) and include the auth code in the request url.
print "Auth code: "
auth_client.code = gets
else
#If authorization has already been given and refresh token saved previously, simply set the refresh code here.
auth_client.refresh_token = File.read('refresh_token.txt')
end
#Now, get our access token which is what we will need to work with the API.
auth_client.fetch_access_token!
if !refresh_token_available
#Save refresh_token for next time
#Note: auth_client.refresh_token is only available the first time after OAuth permission is granted.
#If you need it again, the Google Account owner would have deauthorize your app and you would have to request access again.
#Therefore, it is important that the refresh token is saved after authenticating the first time!
File.open('refresh_token.txt', 'w') { |file| file.write(auth_client.refresh_token) }
refresh_token_available = true
end
api_client = Google::APIClient.new
cal = api_client.discovered_api('calendar', 'v3')
#Get Event List
puts "Getting list of events..."
list = api_client.execute(:api_method => cal.events.list,
:authorization => auth_client,
:parameters => {
'maxResults' => 20,
'timeMin' => '2014-06-18T03:12:24-00:00',
'q' => 'Meeting',
'calendarId' => 'primary'})
puts "Fetched #{list.data.items.count} events..."
#Update Event
puts "Updating first event from list..."
update_event = list.data.items[0]
update_event.description = "Updated Description here"
result = api_client.execute(:api_method => cal.events.update,
:authorization => auth_client,
:parameters => { 'calendarId' => 'primary', 'eventId' => update_event.id},
:headers => {'Content-Type' => 'application/json'},
:body_object => update_event)
puts "Done with update."
#Add New Event
puts "Inserting new event..."
new_event = cal.events.insert.request_schema.new
new_event.start = { 'date' => '2015-01-01' } #All day event
new_event.end = { 'date' => '2015-01-01' }
new_event.description = "Description here"
new_event.summary = "Summary here"
result = api_client.execute(:api_method => cal.events.insert,
:authorization => auth_client,
:parameters => { 'calendarId' => 'primary'},
:headers => {'Content-Type' => 'application/json'},
:body_object => new_event)
puts "Done with insert."
I'm trying to get an oauth token I can use with gmail_xauth (ruby gem)
to look at a user's mail. I first registered my app with google and
then set up devise to request access to mail:
config.omniauth :google, 'key', 'secret', :scope => 'https://mail.google.com/mail/feed/atom/'
I then go through the outh/openid flow and google prompts me to
approve access to gmail, redirecting me back to the app with a a token
and secret in the omniuth credentials & my Google account lists my app
as authorized to access my data. So far so good.
Now, when I take those credentials and try to use them with
gmail_xoauth like so:
require 'gmail_xoauth'
imap = Net::IMAP.new('imap.gmail.com', 993, usessl = true, certs =
nil, verify = false)
imap.authenticate('XOAUTH', '...#gmail.com',
:consumer_key => 'key,
:consumer_secret => 'secret',
:token => 'omniauth_returned_token',
:token_secret => 'omniauth_returned_secret'
)
I get an error "Net::IMAP::NoResponseError: Invalid credentials
(Failure)".
Interestingly, following the gmail_xoauth README to generate a token
with an same consumer using a python script it does work.
This works for me:
config.omniauth :google, 'anonymous', 'anonymous', :scope => 'https://mail.google.com/'
I'm using the gmail gem, so to connect it looks like this:
gmail = Gmail.connect(:xoauth, auth.uid,
:token => auth.token,
:secret => auth.secret,
:consumer_key => 'anonymous',
:consumer_secret => 'anonymous'
)
I'm passing an authentication object in, but you'll be getting it from the env variable env["omniauth.auth"]. I'm using anonymous/anonymous for the key/secret since I haven't registered my domain with google, but I believe you can here. It'll still work with anonymous/anonymous, but Google will just warn the user.
Google's OAuth1 protocol is now deprecated and many gems have not yet updated to use their OAuth2 protocol. Here is a working example of fetching email from Google using their OAuth2 protocol. This example uses the mail, gmail_xoauth, omniauth, and omniauth-google-oauth2 gems.
You will also need to register your app in Google's API console in order to get your API tokens.
# in an initializer:
ENV['GOOGLE_KEY'] = 'yourkey'
ENV['GOOGLE_SECRET'] = 'yoursecret'
Rails.application.config.middleware.use OmniAuth::Builder do
provider :google_oauth2, ENV['GOOGLE_KEY'], ENV['GOOGLE_SECRET'], {
scope: 'https://mail.google.com/,https://www.googleapis.com/auth/userinfo.email'
}
end
# ...after handling login with OmniAuth...
# in your script
email = auth_hash[:info][:email]
access_token = auth_hash[:credentials][:token]
imap = Net::IMAP.new('imap.gmail.com', 993, usessl = true, certs = nil, verify = false)
imap.authenticate('XOAUTH2', email, access_token)
imap.select('INBOX')
imap.search(['ALL']).each do |message_id|
msg = imap.fetch(message_id,'RFC822')[0].attr['RFC822']
mail = Mail.read_from_string msg
puts mail.subject
puts mail.text_part.body.to_s
puts mail.html_part.body.to_s
end