I am developing my Rails 3 application that uses Twitter OAuth and I am getting troubles because apparently I can't get the access_token, after clicking 'Allow' and Twitter redirecting me back to my application url, when I go to twitter.com/settings/connections I can't see my app there as authorized. I guess there is something wrong in my controller, I hope you can point them:
class OauthController < ApplicationController
def start
request_token = client.get_request_token(:oauth_callback => 'http://localhost:3000')
session[:request_token] = request_token.token
session[:request_token_secret] = request_token.secret
redirect_to request_token.authorize_url
end
def callback
#access_token = client.get_access_token(:oauth_verifier => params[:oauth_verifier])
render :json => access_token_get('https://api.twitter.com/account/verify_credentials.json')
end
protected
def client
#consumer = OAuth::Consumer.new(
'key','secret',
:site => 'https://api.twitter.com',
:authorize_url => 'https://api.twitter.com/oauth/authorize',
:access_token_url => 'https://api.twitter.com/oauth/access_token'
)
end
end
Please help, tell me where is my mistake, thanks for the attention!
Rodrigo Alves Vieira.
I'm not exactly sure what part of your code isn't working, probably something to do with the access_token_get method, but I'll show you how I did it--maybe it'll help..
after the line where you initialize #access_token, I do something like this:
#response = client.request(:get, "/account/verify_credentials.json", #access_token, { :scheme => :query_string })
case #response
when Net::HTTPSuccess
user_info = JSON.parse(#response.body)
unless user_info['screen_name']
# authentication failed, error handling
end
# We have an authorized user, save the information to the database using #access_token.token and #acess_token.secret
else
# error handling
end
(oh, and i was using the json gem, so make sure to gem install json and require 'json' at the top)
Hope that helps!
Related
I am trying to authenticate my new Shopify app. First, my authenticate method redirects the shop owner to Shopify's authentication page:
def authenticate
ShopifyAPI::Session.setup({:api_key => "123", :secret => "456"})
session = ShopifyAPI::Session.new("someshop.myshopify.com")
redirect_to session.create_permission_url(["read_orders"], "https://myapp.com/shopify/post_authenticate?user=someshop")
end
Once the shop owner has approved the integration, the redirect uri triggers my post_authenticate method:
def post_authenticate
ShopifyAPI::Session.setup({:api_key => "123", :secret => "456"})
session = ShopifyAPI::Session.new("#{params[:user]}.myshopify.com")
token = session.request_token(:code => params[:code], :signature => params[:signature], :timestamp => params[:timestamp])
end
But the request_token method returns the following error:
#<ShopifyAPI::ValidationException: Invalid Signature: Possible malicious login>
I have read somewhere that you need to be in the same ShopifyAPI session while doing all of this, but it does not say so in the documentation. And the example app takes a very different approach than the documentation.
As per my comment, I utilize the omniauth methodology for authenticating. Here's a gist of the code for reference. https://gist.github.com/agmcleod/7106363317ebd082d3df. Put all the snippets below.
class ApplicationController < ActionController::Base
protect_from_forgery
force_ssl
helper_method :current_shop, :shopify_session
protected
def current_shop
#current_shop ||= Shop.find(session[:shop_id]) if session[:shop_id].present?
end
def shopify_session
if current_shop.nil?
redirect_to new_login_url
else
begin
session = ShopifyAPI::Session.new(current_shop.url, current_shop.token)
ShopifyAPI::Base.activate_session(session)
yield
ensure
ShopifyAPI::Base.clear_session
end
end
end
end
In my login controller:
def create
omniauth = request.env['omniauth.auth']
if omniauth && omniauth[:provider] && omniauth[:provider] == "shopify"
shop = Shop.find_or_create_by_url(params[:shop].gsub(/https?\:\/\//, ""))
shop.update_attribute(:token, omniauth['credentials'].token)
shopify_session = ShopifyAPI::Session.new(shop.url, shop.token)
session[:shop_id] = shop.to_param
redirect_to root_url
else
flash[:error] = "Something went wrong"
redirect_to root_url
end
end
config/initializers/omniauth.rb
Rails.application.config.middleware.use OmniAuth::Builder do
provider :shopify, Settings.api_key, Settings.api_secret,
scope: 'write_products,write_script_tags,read_orders',
setup: lambda { |env| params = Rack::Utils.parse_query(env['QUERY_STRING'])
env['omniauth.strategy'].options[:client_options][:site] = "http://#{params['shop']}" }
end
Then in your routes file, map the create action of your session appropriately:
match '/auth/shopify/callback', :to => 'login#create'
From there i use the shopify_session method as an around filter on the appropriate controllers.
Been trying to get fb_graph working so i can get things like someones friendlist and i cannot get rid of this error. The ActiveSupport::Memoizable is included in the facebook class. Trying figure it out from a fb_graph example application here https://github.com/nov/fb_graph_sample
image of error: http://imgur.com/VXSHhJf
facebook model:
class Facebook < ActiveRecord::Base
def profile
#profile ||= FbGraph::User.me(self.access_token).fetch
end
class << self
extend ActiveSupport::Memoizable
def config
#config ||= if ENV['fb_client_id'] && ENV['fb_client_secret'] && ENV['fb_scope']
{
:client_id => ENV['fb_client_id'],
:client_secret => ENV['fb_client_secret'],
:scope => ENV['fb_scope'],
}
else
YAML.load_file("#{Rails.root}/config/facebook.yml")[Rails.env].symbolize_keys
end
rescue Errno::ENOENT => e
raise StandardError.new("config/facebook.yml could not be loaded.")
end
def app
FbGraph::Application.new config[:client_id], :secret => config[:client_secret]
end
def auth(redirect_uri = nil)
FbGraph::Auth.new config[:client_id], config[:client_secret], :redirect_uri => redirect_uri
end
def identify(fb_user)
_fb_user_ = find_or_initialize_by_identifier(fb_user.identifier.try(:to_s))
_fb_user_.access_token = fb_user.access_token.access_token
_fb_user_.save!
_fb_user_
end
end
end
and here is facebooks_controller
require 'rack/oauth2'
class FacebooksController < ApplicationController
before_filter :require_authentication, :only => :destroy
rescue_from Rack:.center.hero-unit
%h1 Welcome to Dropshare
%h2
This is the home page for Dropshare
%p (at least for time being)
= render 'layouts/facebook_signup'
= render 'layouts/drive_signup'
/
<haml:loud> provide(:title, 'Home')</haml:loud>
<h1>Home</h1>
<p>This is the home page (for the time being) for Dropshare</p>
Sign up now!
:OAuth2::Client::Error, :with => :oauth2_error
# handle Facebook Auth Cookie generated by JavaScript SDK
def show
auth = Facebook.auth.from_cookie(cookies)
authenticate Facebook.identify(auth.user)
redirect_to dashboard_url
end
# handle Normal OAuth flow: start
def new
client = Facebook.auth(callback_facebook_url).client
redirect_to client.authorization_uri(
:scope => Facebook.config[:scope]
)
end
# handle Normal OAuth flow: callback
def create
client = Facebook.auth(callback_facebook_url).client
client.authorization_code = params[:code]
access_token = client.access_token! :client_auth_body
user = FbGraph::User.me(access_token).fetch
authenticate Facebook.identify(user)
redirect_to dashboard_url
end
def destroy
unauthenticate
redirect_to root_url
end
private
def oauth2_error(e)
flash[:error] = {
:title => e.response[:error][:type],
:message => e.response[:error][:message]
}
redirect_to root_url
end
end
Solution
replace
ActiveSupport::Memoizable
with memoist and require 'memoist'
I think you may be running into the fact that ActiveSupport::Memoizable was deprecated & removed from Rails.
https://github.com/rails/rails/commit/36253916b0b788d6ded56669d37c96ed05c92c5c
The author of that gem is running this version of Rails in their gemfile, so I would presume it's supported through this:
gem 'rails', '~>3.2.11'
I'm guessing you're running a newer version of Rails.
I'm new to Rails and have been writing a simple app to post to Tumblr. I got all my oauth stuff working, and decided to use the tumblr_client gem to facilitate posting. I can get it to post just fine through the console, but the same code does not do anything in the controller. It doesn't throw any errors, it just does nothing. Any suggestions? (I censored the blog with {blogname}, but it is correct in my code)
def post
#user = Tumblog.find_by_user_id(5)
#client = Tumblr::Client.new(:consumer_key => #key, :consumer_secret => #secret, :oauth_token => #user.oauth_token, :oauth_token_secret => #user.oauth_secret)
#client.text("{blogname}.tumblr.com", :body => "test", :state => "draft")
redirect_to "http://www.tumblr.com/blog/{blogname}/drafts"
end
It turns out that it was a conflict with my instance variable name. Changed #client to #clients and it worked just fine.
I've set up authentication with the Foursquare API and my Rails app, and now it's time to add functionality. I am not too proficient with Rails - it is not my first language. I want to allow a merchant to connect with Foursquare (Working) and then direct the merchant to a page where they can see unique visitors to their venue, the number of checkins to the venue, and who the mayor of the venue is. I know what endpoints to use, I'm just not sure how to implement them in rails. (Access Token, etc.)
Thanks!
After Answer
I'm trying to implement Turd Ferguson's answer, but I'm not getting anywhere. I keep getting an error saying the method is undefined. I want to try a simple venue search as soon as the user is authenticated. (Create Action)
Also, I'm using OmniAuth for authentication.
sessions_controller.rb
class SessionsController < ApplicationController
require 'foursquare'
def create
auth_hash = request.env['omniauth.auth']
venues = Foursquare::search_venues("starbucks")
render :text => venues
end
def failure
end
def destroy
session[:user_id] = nil
render :text => "Logged out!"
end
def callback
code = params[:code]
#access_token = foursquare.access_token(code, callback_session_url)
session[:access_token] = #access_token
redirect_to examples_path
end
end
foursquare.rb
class Foursquare
def self.search_venues(text)
client.search_venues(:ll => '36.142064,-86.816086', :query => text)
end
def self.client
#client ||= Foursquare2::Client.new(:client_id => '0YO3F0JNZIPVKG1DE01MNPB132D4JZ0QYRQSOWTZQKHHOPKB', :client_secret => 'GMBOGWUNL2GIKZZXQPSLE4BMFNGB5LDHQREH2UKUCK1TJ1L0')
end
end
Have you looked into using a gem such as foursquare2?
Using the gem you could create a Foursquare class like:
class Foursquare
def self.search_venues(text)
client.search_venues(:ll => '36.142064,-86.816086', :query => text)
end
def self.client
#client ||= Foursquare2::Client.new(:client_id => 'your_client_id', :client_secret => 'your_secret')
end
end
You could then call this anywhere you wanted by doing something like:
venues = Foursquare::search_venues "foobar"
I'm having trouble using omniauth & twitter gem to generate tweets.
I have been using this tutorial http://blog.assimov.net/post/2358661274/twitter-integration-with-omniauth-and-devise-on-rails-3
and I can log in using twitter, generate authentications but I cannot update tweets.
current_user.twitter.update("My Rails 3 App with Omniauth, Devise and Twitter")
This line complains about the method update.
What confuses me about the tutorial above is that at the beginning they generate a migration to store the secret in authentications, but at no point later in the tutorial is any mention of changing any code to write the secret to the database.
My understanding is that the secret is obtained from the omniauth hash that is stored in the session cookie. What am I missing here?
def hash_from_omniauth(omniauth)
{
:provider => omniauth['provider'],
:uid => omniauth['uid'],
:token => (omniauth['credentials']['token'] rescue nil),
:secret => (omniauth['credentials']['secret'] rescue nil)
}
end
So everything seems to be working apart from creating the Twitter Client hence not having the update method available?
current_user.twitter.update("first tweet")
The twitter method here should be creating the Twitter Client
def twitter
debugger
unless #twitter_user
provider = self.authentications.find_by_provider('twitter')
#twitter_user = Twitter::Client.new(:oauth_token => provider.token, :oauth_token_secret => provider.secret )rescue nil
end
#twitter_user
end
I'm sorry I'm not great at explaining the problem. Any help greatly appreciated.
Thanks
L
If you only need to post to twitter, it might just be easier to forgo the twitter gem completely. The consumer / access token generation requires the app id and secret as well as the user's access and secret tokens. I found this to be easy enough to implement that I thought the overhead of the twitter gem wasn't necessary.
module User::Social
def self.included(base)
base.instance_eval do
include Rails.application.routes.url_helpers
end
end
def promote_activity(type, profile)
url = short_profile_url(profile, :host => Conf.domain)
tw_client.request(:post, "http://api.twitter.com/1/statuses/update.json", :status => I18n.translate("tweets.#{type}", :profile => profile.to_s, :url => url))
end
def tw_client
#tw_client ||= begin
consumer = OAuth::Consumer.new(Conf.tw_app_id, Conf.tw_secret, :site => 'http://api.twitter.com')
OAuth::AccessToken.from_hash(consumer, {:oauth_token => self.access_token, :oauth_token_secret => self.secret_token})
end
end
end
class User < AR::Base
include User::Social
end