Twitter Streaming API with OAuth? - ruby-on-rails

I've been stuck on this for awhile. Does anyone know how to authenticate the Twitter Streaming API requests using OAuth? As of right now I'm authenticating via Basic Authentication, and I would like to completely switch over to OAuth. Also, I'm using Ruby on Rails if that helps.
Thanks

Connecting to the Twitter Streaming API via OAuth is done much the same as connecting via the REST API. Assuming you've already negotiated an access token, you sign and issue the request using the same signing algorithm as for a REST request. With the Streaming API, it's best to use header-based OAuth rather than query-string based.
Here's an example of a signed OAuth-based request for the sample end point:
GET http://stream.twitter.com/1/statuses/sample.json
Signature Base String example:
GET&http%3A%2F%2Fstream.twitter.com%2Fstatuses%2Fsample.json&oauth_consumer_key%3Dri8JxYK2ddwSV5xIUfNNvQ%26oauth_nonce%3DUJb0f3nHhFQkpkWkJzxnFT65xX1TZeuGjww6Q2XWs4%26oauth_signature_method%3DHMAC-SHA1%26oauth_timestamp%3D1306947138%26oauth_token%3D819797-torCkTs0XK7H2Y2i1ee5iofqkMC4p7aayeEXRTmlw%26oauth_version%3D1.0
Authorization Header after signing:
Authorization: OAuth oauth_consumer_key="ri8JxYK2ddwSV5xIUfNNvQ", oauth_nonce="UJb0f3nHhFQkpkWkJzxnFT65xX1TZeuGjww6Q2XWs4", oauth_signature="bN14zlBIdCZCSl9%2B8UV8dB2VWjI%3D", oauth_signature_method="HMAC-SHA1", oauth_timestamp="1306947138", oauth_token="819797-torCkTs0XK7H2Y2i1ee5iofqkMC4p7aayeEXRTmlw", oauth_version="1.0"
Matt Harris has some sample code in PHP demonstrating connecting to the streaming API via OAuth: https://github.com/themattharris/tmhOAuth/blob/master/examples/streaming.php

After you register your application on http://dev.twitter.com this is how it's done in Perl:
#!/usr/bin/perl
use strict;
use AnyEvent::Twitter::Stream;
if ($ENV{FIREHOSE_SERVER}) {
$AnyEvent::Twitter::Stream::STREAMING_SERVER = $ENV{FIREHOSE_SERVER};
}
my $done = AE::cv;
binmode STDOUT, ":utf8";
my $streamer = AnyEvent::Twitter::Stream->new(
consumer_key => 'KEY',
consumer_secret => 'SECRET',
token => 'TOKEN',
token_secret => 'TOKEN SECRET',
method => "filter",
track => "KEYWORDS TO TRACK",
on_tweet => sub {
# CUSTOM CODE HERE
},
on_error => sub {
my $error = shift;
warn "ERROR: $error";
$done->send;
},
on_eof => sub {
$done->send;
},
);
$done->recv;

Try the OmniAuth gem which supports many external providers https://github.com/intridea/omniauth

You should use this gem : Tweetstream which sits on top of em-twitter

Related

Is it possible to use OAuth 2.0 for Office365 SMTP?

I have an email application for sending emails that was written in house. We have set it with the option to use OAuth 2.0 with GMail (personal and business accounts) and Outlook.com accounts without issues.
We can also authentication with user ids and passwords but we prefer OAuth 2.0 as we don't save passwords anywhere that way.
We now have requests to do this for Office365 accounts.
I notice that the hello message on the Office365 smtp server (smtp.office365.com port 587) does not offer the XOAUTH2 option.
250-BY2PR0601CA0005.outlook.office365.com Hello [xx.xx.xx.xx]
250-SIZE 157286400
250-PIPELINING
250-DSN
250-ENHANCEDSTATUSCODES
250-AUTH LOGIN
250-8BITMIME
250-BINARYMIME
250 CHUNKING
But, the SMTP server for outlook.com does:
250-BLU436-SMTP14.smtp.hotmail.com Hello [xx.xx.xx.xx]
250-TURN
250-SIZE 41943040
250-ETRN
250-PIPELINING
250-DSN
250-ENHANCEDSTATUSCODES
250-8bitmime
250-BINARYMIME
250-CHUNKING
250-VRFY
250-AUTH LOGIN PLAIN XOAUTH2
250 OK
Is this possible to do with Office365? If not, can we point Office365 users to the outlook.com smtp server (smtp-mail.outlook.com) or are they totally different?
We'd rather not use the APIs just for sending emails if possible as the RESTful APIs for each provider will of course be quite different.
The reason for using OAuth 2.0 when sending email with an Office365 account is that we don't want to have to store passwords on our server. Also, if the user changes their password, we won't know unless they tell us or manually update it on our system side.
Using OAuth 2.0 this would solve this problem and allow the application to flow like with other email providers.
I really wanted this feature too. It would make Office365 apps that need to send mail that much easier!
I did some hunting, and found this which appears to be as close to an official answer as we are going to get (and the answer is a flat no).
Not sure if I'm missing something, but isn't this what you want? Looks like this was posted back in February. Interestingly, this article says that Oauth is supported for M365, but NOT for outlook.com users.
https://learn.microsoft.com/en-us/exchange/client-developer/legacy-protocols/how-to-authenticate-an-imap-pop-smtp-application-by-using-oauth
I made one example using javax.Mail and OAuth for desktop application. It opens logon screen to get acccessToken. I followed multiple instructions so probably there are too many permissions and props in JavaMail but I succeeded to send mail.
My example program (Github)
PHP Example with OAuth2.
[On GitHub] (https://github.com/larsonnn/php_smtp_xoauth2_microsoft.php)
<?php
/* composer.json
"require": {
"phpmailer/phpmailer": "^6.6",
"league/oauth2-client": "^2.6",
"thenetworg/oauth2-azure": "^2.1"
}
*/
use PHPMailer\PHPMailer\Exception;
use PHPMailer\PHPMailer\OAuth;
use PHPMailer\PHPMailer\SMTP;
use PHPMailer\PHPMailer\PHPMailer;
use TheNetworg\OAuth2\Client\Provider\Azure;
require "vendor/autoload.php";
$mail = new PHPMailer(true);
$provider = new Azure([
'clientId' => '',
'clientSecret' => '',
"scopes" => ["https://outlook.office.com/SMTP.Send"],
"tenant" => "",
"defaultEndPointVersion" => Azure::ENDPOINT_VERSION_2_0,
]);
$mail->setOAuth(
new OAuth(
[
'provider' => $provider,
'clientId' => '',
'clientSecret' => '',
'refreshToken' => '',
'userName' => 'mymail#office_365_email.tld',
]
)
);
//Server settings
$mail->SMTPDebug = SMTP::DEBUG_SERVER;
$mail->isSMTP();
$mail->Host = 'smtp.office365.com';
$mail->Port = 587;
$mail->SMTPAuth = true;
$mail->AuthType = 'XOAUTH2';
$mail->SMTPSecure = PHPMailer::ENCRYPTION_STARTTLS;
$mail->CharSet = PHPMailer::CHARSET_UTF8;
//Recipients
$mail->setFrom('mymail#office_365_email.tld', 'name');
$mail->addAddress('spam#example.tld', 'Spam');
//Content
$mail->Subject = 'Here is the subject';
$mail->Body = 'Hallo';
$mail->AltBody = 'This is the body in plain text for non-HTML mail clients';
$mail->send();

rails google-api-client contact api

I want to get access to a user's contact list with the google contacts API.
I've managed to get the token and refresh token and I'm now trying to use then on my rails server.
The google-api-client gem seems to be the way to go but I could not find which discovered_api to use. Greg Baugues provides a great tuto to get the gmail API working. The general request seems to look like
client = Google::APIClient.new
client.authorization.access_token = user_token
service = client.discovered_api('gmail')
result = client.execute(
:api_method => service.users.labels.list,
:parameters => {'userId' => 'me'},
:headers => {'Content-Type' => 'application/json'})
pp JSON.parse(result.body)
But I could not find how to query it for contacts. Running
client.discovered_apis.each do |gapi|
puts "#{gapi.title} \t #{gapi.id} \t #{gapi.preferred} \n"
end
(from here) shows now API related to contacts and I'm wondering if this is implemented in the alpha version of the gem...
As mentioned by #abraham, the Google contact API is not supported by the discovery API. Here is how I did it in ruby from the access token using the gems google_contacts_api and oauth2 (thanks to Rael Gugelmin Cunha for pointing them to me):
client = OAuth2::Client.new(client_id, client_secret, site: url)
token = OAuth2::AccessToken.new(client, access_token)
google_contacts_user = GoogleContactsApi::User.new(token)
contacts = google_contacts_user.contacts
There might be some more elegant way to do it but this works :)
The Google Contacts API is on Google's older GData API standard and is not supported by the discovery API. There is a pretty extensive guide for plain Ruby and a helper gem. Retrieving all contacts doesn't provide a Ruby sample but the Python sample should translate pretty easily.
def PrintAllContacts(gd_client):
feed = gd_client.GetContacts()
for i, entry in enumerate(feed.entry):
print '\n%s %s' % (i+1, entry.name.full_name.text)
if entry.content:
print ' %s' % (entry.content.text)
# Display the primary email address for the contact.
for email in entry.email:
if email.primary and email.primary == 'true':
print ' %s' % (email.address)

Authentication Error When Trying to Access Jawbone API (RoR)

I am trying to access the Jawbone API in my Rails app using omniauth + jawbone. I have a button that initiates the OAuth login for the user and I create a user model for this user with a token and a refresh token on my database. (It seems like the OAuth for Jawbone is working since I get the user's information).
I then query the Jawbone API with HTTParty with the user token given to me after the user logs in via Jawbone, but I get the following error:
{"meta"=>{"code"=>401, "error_detail"=>"You must be logged in to perform that action", "error_type"=>"authentication_error", "message"=>"Unauthorized"}, "data"=>{}}
The code I'm using to query the Jawbone API is:
token = current_user.token
#result = HTTParty.get('https://jawbone.com/nudge/api/v.1.0/users/#me/moves',
:headers => { "Authorization: Bearer" => "#{token}"}
)
I've been searching on the Jawbone API documentation, but can't seem to find an answer. On the Jawbone documentation it says an authentication error means "The request requires an authenticated user and no user was logged in." So does logging in via OAuth not actually log them in even though I now have a token?
Thanks for the help! I've been struggling with this.
For those that are struggling, it's not
{ "Authorization: Bearer" => "{{token}}" }
The correct header is
{ "Authorization" => "Bearer {{token}}" }
Here is a working code.
You can try this { "Authorization: Bearer " => "#{token}"}.
I have added an extra space after Bearer. I had a problem like this and I had to put an extra space. One more thing you should use the updated api which is: "https://jawbone.com/nudge/api/v.1.1/users/#me/moves"

Cannot get oAuth2 Access Token for Google Analytics API

I am using Rails + Garb Gem (Sija Branch) + omniauth-google-oauth2 Gem and I can successfully authenticate with the Google Analytics API and extract data that our app is generating when using a user login, e.g.:
Garb::Session.login('USERNAME', '<PASSWORD>')
I can then use Garb to connect to the Analytics Profile I want and pull the data from it and display some charts on a webpage. This all works fine.
However, I want to use oAuth2 to authenticate with Analytics which is why I had to install the Sija branch of the Garb Gem from Github (it supports oAuth2) and I also installed the omniauth-google-oauth2 Gem. Now in theory I should be able to authenticate using the following code:
Garb::Session.access_token = access_token # an instance of OAuth2::Client
It's at this point that it gets a little hazy for me and I would greatly appreciate some guidance. Here's how far I have gotten:
1) I created a Project in the Google API console and turned on Analytics API under Services
2) This provided me with a Client ID and Client Secret
3) I came across this code which I could populate with the ID and Secret above:
client = OAuth2::Client.new(
GOOGLE_CLIENT_ID,
GOOGLE_CLIENT_SECRET,
{
:site => 'https://accounts.google.com',
:authorize_url => '/o/oauth2/auth',
:token_url => '/o/oauth2/token'
})
4) Then there is the next bit of code:
response = OAuth2::AccessToken.new(
client,
STORED_TOKEN, {
refresh_token: STORED_REFRESH_TOKEN,
expires_at: STORED_EXPIRES_AT
})
5) and then in theory connect with:
Garb::Session.access_token = response
The problem I have is I don't have the token information in Point (4) above. It seems to me that with oAuth2 I need to do a "handshake" once and print out the return token values? Perhaps through Rails code which prints the values returned out and then paste the token values into a constant in the Rails app so that I can use them in the above code? I really am confused. As I mentioned earlier, the web app works fine using the user login authentication. All the web app is doing is authenticating with analytics, pulling down some data and drawing a chart. But I am stuck converting it over to oAuth2 as I just do not know how to get the Access Token that the Garb Gem is looking for. I should also note that this is not a public website with multiple users authenticating, this is a CMS website that is connecting to our own Analytics data.
I have seen some partial snippets of aspects of this but not a fully explained or working example. I would really appreciate any guidance and help with this question.
Many thanks in advance,
JR
I've soldiered through this over the last few weeks, so let me share what worked:
To use Oauth2 you need to get a 'refresh token' that you use to 're-authenticate' with google each time you make an API call. The steps for this are as follows:
1) Setup your account in the API console - https://code.google.com/apis/console/b/0/ (seems like you've done that well)
2) In your API account, make sure you have a redirect URI pointing back to your application:
http://some-url.com/auth/google_oauth2/callback
http://localhost:3000/auth/google_oauth2/callback
Note here that google won't let you call back to your local machine as 0.0.0.0:3000... so you'll need to use localhost explicitly
3) In your route file, tie that redirect url to an action in the controller where you're going to create the project or authentication
match '/auth/:provider/callback' => 'authentications#create'
The ':provider' simply lets you match on multiple types of oauth, but you could just put 'google_oauth2' there as well.
4) Now create that action in your controller
def create
auth = request.env["omniauth.auth"]
params = request.env["omniauth.params"]
project = Project.find(params['project_id'])
Authentication.create(:project_id => project.id, :provider => auth['provider'], :uid => auth['uid'], :access_token => auth['credentials']['refresh_token'])
flash[:notice] = "Authentication successful."
redirect_to owner_view_project_path(project)
end
5) The controller action should retrieve the relevant fields from the response object (details of response object here: https://github.com/zquestz/omniauth-google-oauth2) - in particular, you need to get the 'refresh_token' and save that to your project or authentication object - if you haven't added an 'access_token' attribute to the desired object, go do that now with a migration, then start saving the refresh token to that attribute
6) Now when you're ready to call that particular authentication and get API data for it, you can load up that object where you saved the access token, and use that to get a new session with the google API as follows:
#authentication = Authentications.find(params[:id])
client = OAuth2::Client.new GOOGLE_CLIENT_ID, GOOGLE_CLIENT_SECRET,
{
:site => 'https://accounts.google.com',
:authorize_url => "/o/oauth2/auth",
:token_url => "/o/oauth2/token",
}
response = OAuth2::AccessToken.from_hash(client, :refresh_token => #authentication.access_token).refresh!
Garb::Session.access_token = response
#profiles = Garb::Management::Profile.all
What this code did was create an OAuth2 access token (response) by specifying the client and then a refresh_token, then calling 'refresh!' to get a refreshed access token... then use that access token to establish your Garb session, then call down all the profiles for a given account using the Gard::Management::Profile.all
Hope this helps - let me know if you have questions!
Just a note on what worked for me in:
For steps 3, 4 & 5 I used cURL instead to retrieve the Access/Refresh token. Step 6 is then the same for me (using the Sija branch of the Garb Gem). So using cURL:
Using the details associated with your Google app POST the following using cURL:
curl --data "code=<APP_CODE>&redirect_uri=http://localhost:3000/oauth2callback&client_id=<CLIENT_ID>.apps.googleusercontent.com&scope=&client_secret=<CLIENT_SECRET>&grant_type=authorization_code" https://accounts.google.com/o/oauth2/token
The response takes the form:
{
"access_token" : "<ACCESS_TOKEN>",
"token_type" : "Bearer",
"expires_in" : 3600,
"refresh_token" : "<REFRESH_TOKEN>"
}
which you can plug into the Garb Gem as per part 6.
The answer by #CamNorgate is valid.
If you don't have a "refresh_token" back from Omniauth on the callback make sure you are correctly initializing :google_oauth2
Rails.application.config.middleware.use OmniAuth::Builder do
provider :google_oauth2, ENV["GOOGLE_CLIENT_ID"], ENV["GOOGLE_CLIENT_SECRET"],
{ :scope=>"https://www.google.com/m8/feeds, https://www.googleapis.com/auth/userinfo.email, https://www.googleapis.com/auth/userinfo.profile",
:approval_prompt=>"force", access_type="offline"
}
end
Make sure to include :approval_prompt=>"force", access_type="offline" in order for the refresh_token to be sent back. The refresh_token is only provided on the first authorization from the user.

Yahoo API with Ruby on Rails and OAUTH2

I have an RoR site that gets data from stock exchanges and I am using Yahoo's finance table via the Yahoo API. I need authorization to gain full access to YQL, which requires that I use Oauth2. I need help getting OAuth access to Yahoo.
This is what I have tried:
client = OAuth2::Client.new(oauth_consumer_key,oauth_consumer_secret, {
access_token_path: '/oauth/v2/get_token',
authorize_path: '/oauth/v2/request_auth',
authorize_url: 'https://api.login.yahoo.com/oauth/v2/request_auth',
request_token_path: '/oauth/v2/get_request_token',
site: 'https://api.login.yahoo.com'
})
puts client.auth_code.authorize_url( redirect_uri: "http://localhost:3000")
code = gets.chomp
token = client.auth_code.get_token(code, redirect_uri: "http://localhost:3000")
I don't know which "code" I must use. Authorize_url returns me this URL, but it is unclear what the "code". I was inspired by this Question.
Don't ask me why but Yahoo has made it very hard to find their OAuth 2.0 documention. I found it, though!
Also, pretty "awesome" that you get a refresh_token without needing to explicitly ask the user for "offline" permissions. In my opinion, this is a security concern for Yahoo. Both Google and Microsoft require explicit "offline" access.
require 'oauth2'
OAuth2::Client.new(Rails.application.secrets.yahoo_consumer_id, Rails.application.secrets.yahoo_consumer_secret, site: 'https://api.login.yahoo.com', authorize_url: '/oauth2/request_auth', token_url: '/oauth2/get_token')
client.auth_code.authorize_url(redirect_uri: redirect_uri, headers: { "Authorization" => basic_authorization })
token = client.auth_code.get_token(code, redirect_uri: redirect_uri)
# Later
token.refresh!
As per quatermain's request, I post my solution as answer here:
https://docs.google.com/document/d/1SdGSfakQM3ZuiqJK7keXhOfh6310-z_h0THl1_Jswxk/pub
P/S: There is some mistype I made within the document, as below:
The sentence: "I don't this this URL affect to authentication process..." --> shoud be "I don't think this URL affect to authentication process..."
The word "and ready through" --> should be "and read through"

Resources