401 error with Ruby OAuth for Twitter - ruby

xI've been working for days to get Twitter to authenticate with Ruby, but I'm not having any luck.
My first attempt was something like this:
class TwitterController < ApplicationController
def index
#callback_url = "http://dev.twipler.com:3000/twitter/auth"
#auth= TwitterOAuth::Client.new( :consumer_key => "xxx", :consumer_secret => "xxxxxxxxxxxxxxxxx" )
#rtoken = #auth.request_token :oauth_callback => #callback_url
#token = #rtoken.token
#secret = #rtoken.secret
#link = #rtoken.authorize_url
session['token' ] = #token
session['secret'] = #secret
redirect_to #link
end
def auth
#auth.authorize_from_request(session[:rtoken], session[:rsecret], params[:oauth_verifier])
end
end
And a very similar way but with the Twitter gem, and the same with the OAuth gem directly. No matter what OAuth::Consumer::token_request dies with a 401 error.
So, out of desperation I attempted to git clone Snitter, add my Twitter creds, and try it, but it too dies with a 401.
I've tried using localhost:300/twitter/auth, http://dev.twipler.com:3000/twitter/auth, and a bit.ly for each of the former 2. Nothing works.
Any help?
EDIT: Of course I would forget to do the most logical thing to do and delete my secrets. (They've been changed ;)).

You may want to edit your consumer secret out. With that, anyone can make requests on behalf of your app.
That said, make sure your system time is synced to an ntp server. If your system time has drifted fast or slow, OAuth requests will fail, since their include a timestamp and relatively short TTL. I had this exact problem a while back.
Failing that, you can crack open the oauth gem and turn on HTTP debugging, which will show you the full HTTP transaction including any error message returned.

Related

OAuth request to Google succeeds locally, but fails with "invalid_grant" on Heroku

I'm using a Google service account to make API calls for my Dashing dashboard to Analytics. I'm using the Legato gem to get Analytics data, and authenticating using the gem's wiki's instructions for service accounts.
I've put my Google username and private key into ENV (after base 64-encoding it), and am using dotenv to synchronize these settings between local and Heroku (heroku config confirms that everything is set correctly). So, my authentication code looks like this:
class GoogleAnalyticsAccount
attr_accessor :user, :profile
# Thanks to the "Service Accounts" section at
# https://github.com/tpitale/legato/wiki/OAuth2-and-Google
def initialize scope="https://www.googleapis.com/auth/analytics.readonly"
client = Google::APIClient.new application_name: '[App name]',
application_version: '1.0'
key = Google::APIClient::PKCS12.load_key(Base64.decode64(ENV['GOOGLE_PRIVATE_KEY_BASE64']), "notasecret")
service_account = Google::APIClient::JWTAsserter.new(ENV['GOOGLE_USER'], scope, key)
client.authorization = service_account.authorize
oauth_client = OAuth2::Client.new("", "", {
:authorize_url => 'https://accounts.google.com/o/oauth2/auth',
:token_url => 'https://accounts.google.com/o/oauth2/token'
})
token = OAuth2::AccessToken.new(oauth_client, client.authorization.access_token)
#user = Legato::User.new(token)
end
def profile
#user.profiles.first
end
end
Locally, this code works just fine. On Heroku, I get the following response from Google:
{
"error": "invalid_grant"
}
No more detail than that. Based on extensive Googling, I've found that the two most likely reasons for this are A) I've hit my request limit (but it can't be that, because the same credentials work locally), and B) the server clock isn't synced with NTP. I've set the timezone on Heroku to America/Chicago (same as my local machine), but no dice.
Any ideas? Thanks!
Huh. I was using dotenv and heroku-config to push my settings up to Heroku. Turns out, putting my GOOGLE_USER and GOOGLE_PRIVATE_KEY_BASE64 inside quote marks in my .env file was taken literally by heroku-config, and it was pushing those settings with quote marks to my Heroku config. Thus, the username/key were invalid—hence invalid_grant.
And to think I've been working on this problem for days...

Requesting An Access Token from Google API Returns 302

I'm trying to get an access token from Google API in my Ruby on Rails app, as part of an overall goal of setting up a raketask. I am able to get an Auth Code fine, but when I make a post request to get an access token, I am getting a 302 error. I'll describe my current code first, and afterward list how I've tried to solve the problem so far.
Current code:
#users_controller
def auth_access
client = Signet::OAuth2::Client.new(
:authorization_uri => 'https://accounts.google.com/o/oauth2/auth',
:token_endpoint_uri => 'https://accounts.google.com/o/oauth2/token',
:client_id => ENV['OAUTH_CLIENT_ID'],
:client_secret => ENV['OAUTH_CLIENT_SECRET'],
:scope => 'https://www.googleapis.com/auth/analytics.readonly',
:redirect_uri => 'http://localhost:3000/google/auth_callback'
)
redirect_to client.authorization_uri.to_s
end
This part works fine so far. It redirects to the consent page, and when the user agrees it then redirects them to the page with the auth code in the url parameters. Next I take that auth code and try to make a POST request to API for an access token:
#users_controller
def auth_callback
http = Net::HTTP.new('accounts.google.com')
path = '/o/oauth2/token'
data = "code=#{params['code']}&client_id=#{ENV['OAUTH_CLIENT_ID']}&client_secret=#{ENV['OAUTH_CLIENT_SECRET']}&redirect_uri=http://localhost:3000/auth_final&grant_type=authorization_code"
response = http.post(path, data)
end
This when I run into a problem. The Google API returns a 302, and includes a message saying something akin to "we moved to 'https://accounts.google.com/o/oauth2/token'".
Here's how I've tried to fix the problem so far:
I assumed that the problem was that the http.post method is making a call to an http and not https.
I've tried including
http.use_ssl = true
http.ssl_version = :SSLv3
This returns the error "SSL_connect returned=1 errno=0 state=SSLv3 read server hello A: wrong version number".
I can take a guess at what this means, but I am still unsure of what the actual problem is and how to solve it. Googling the error message has not been a help.
In a similar vein, I tried using gems to make the https call for me, in particular HTTParty and Typheous, although I was not able to make any progress with them (and am still not even sure that it's an http/https problem).
I've tried using the Signet-Rails gem. This was the most productive method by far, making a successful API call and returning the information. However, it either wasn't saving the refresh token or I cannot find where it is being saved. As I need access to that token to run the rake tasks, I gave up on Signet-Rails.
I tried using Legato, and was constantly running into various problems. Overall, Legato left me with the impression that it did not integrate getting the auth code, consent and tokens into the app, instead requiring the developer to set those up in advance outside of the app's scope. I want to be able to set up the auth code as part of the app. If I am understanding Legato properly, then it is not the gem I need.
I've also tried other various odds and ends but to no avail. The above solutions were the tactics I kept coming back to. Primarily I'm looking for an answer to what is going wrong in my code, and what is the best avenue to fix it (and if I was going down the right track with any of my attempted solutions above, which one?)
Thanks for taking the time to read this and answer!
(on a complete sidenote, those last three list items should be 2, 3, 4, but the stackoverflow text editor thinks it knows better than me...)
Specify the port:
http = Net::HTTP.new('accounts.google.com', 443)
Source: SSL Error on HTTP POST (Unknown Protocol)

Attempting a PUT to Google Groups API using OAuth2 gem and Ruby

I'm trying to do a PUT call on a Google Groups API using Ruby and the OAuth2 GEM. I've managed to authenticate OK, and the GET call works properly, but I can't seem to get the call to use the PUT method. I thought the following would work, since OAuth2 uses Faraday, but I just keep getting the 400 message back, with an indication that something's "required":
data = access_token.put('https://www.googleapis.com/groups/v1/groups/{email address}?alt=json').parsed do |request|
request.params['email'] = "{email address}"
end
Has anyone got a working example of passing parameters to a PUT request?
OK. Looks like the ".parsed" was interfering with the call here's what works, with some additions to the request object:
response = access_token.put('https://www.googleapis.com/groups/v1/groups/{email address}') do |request|
request.headers['Content-Type'] = 'application/json'
request.body='{"email": "{email address}"}'
end
# check this
puts response.status
# works if it's 200

Implementing Remember Me in Padrino 0.11 with new admin interface

I'm trying to implement a 'Remember Me' feature in the new Padrino 0.11 Admin interface, but having a little bit of trouble due to the differences between it and Rails. Basically, I'm following along with http://railscasts.com/episodes/274-remember-me-reset-password.
I've managed to get the Remember Me and auth_token working handily, and I can see the cookie in the Dev console when I go to look at it. I am having a lot of trouble figuring out how to get the application to do autologin on the cookie when it is present though. I'm sure it's something stupid, but this is where I'm up to.
For instance, I've got the actual Remember Me creating an auth_token and setting it fine to the cookie (I can see it on localhost) in the dev console on Chrome via this in the sessions controller.
admin/controllers/sessions
post :create do
if account = Account.authenticate(params[:email], params[:password])
set_current_account(account)
if params[:remember_me]
response.set_cookie('da_app', value: account.auth_token,
expires: (Time.now + 1.year + 1.day))
end
flash[:success] = "You've successfully logged in as #{account.name}."
redirect url(:base, :index)
else
params[:email], params[:password] = h(params[:email]), h(params[:password])
flash[:error] = pat('login.error')
redirect url(:sessions, :new)
end
end
However, due to my inexperience with padrino, a little stumped as to where I'd put the bit of logic which triggers before an incoming request, checks for the cookie and then logs the user in. I tried the following, which is not perfect but which is definitely not working (though not sure why... =< ) and in fact, the code block to detect the cookie does not even seem to be firing (which seems pretty basic.).
admin/app.rb (not sure this is the right place for it actually)
before '/*' do
if request.cookies['da_app'].exists?
set_current_account(Account.find_by_auth_token(request.cookies['da_app']))
redirect url(:base, :index)
end
end
So, I'm sure it's probably dead simple to solve but a bit stumped on this one (and also, am really trying to avoid using a gem plugin like padrino-warden or the like at the moment and implement this from scratch as an exercise.).
(Also, bonus karma points on helping solve this one as I'm implementing this as part of some pro bono work for a global conservation charity.)

Using Shoes and download over https gives ssl errors

In a shoes application am trying to download stuff from some internal websites. I get this error
Error in /tmp/selfgz14214/ruby/lib/net/protocol.rb line 66
undefined method 'closed?' for #<OpenSSL::SSL::SSLSocket:0xb6af94f0>
I got the above error for this code. This give the above error if used from Shoes.
require 'net/http'
require 'net/https'
require 'rexml/document'
class Blogs
attr_reader :Connection
def initialize
#Connection = Net::HTTP::new("someInternalWebSite", 443)
#Connection.use_ssl = true
end
def get_blogs
doc = REXML::Document.new #Connection.get('/weblogs/feed/entries/atom').body
blogs = Array.new
# ----- some crap to parse the blogs
return blogs
end
end
Note this problem only happens when run from inside shoes.
Also using the inbuilt download method in shoes it doesn't return, not even start event gets raised. The following is the code for that
download "https://internalWebsite/weblogs/feed/entries/atom",
:start => lambda {
alert "hello"
},
:progress => lambda {
alert "progress"
},
:finish => lambda {
alert "finish"
}
I haven't worked with ( or indeed heard of ) shoes, but when I have had problems with accessing stuff over HTTPS in Ruby it has often been a case of not having the certificate set up properly.
My experience with this was a couple of years ago now but it may be worth doing a bit of experimentation just to check that you can actually make a regular SSL connection with that code. I would expect that you would at least need to tell it where to find the client certificate or that it doesn't need a client certificate at all.
I also recall that I needed to use http-access2 rather than the regular http library.
As I say, I'm sure things have moved on since I was trying to do this, but most of the problems I found relating to ssl connections were certificate related.
Shoes doesn't support HTTPS in the current version.

Resources