Rails: Could not authenticate you from Facebook because "Invalid credentials" - facebook

I integrated omniauth-facebook using https://github.com/plataformatec/devise/wiki/OmniAuth%3a-Overview. But I am getting error of :
Could not authenticate you from Facebook because "Invalid credentials".
And in logs, getting this:
Authentication failure! invalid_credentials: OAuth2::Error, : {"error":{"message":"This authorization code has been used.","type":"OAuthException","code":100}}
I have devise installed. When i click on facebook sign in link, it comes back to devise sign "www.mealnut.com/user/sign_in#=" and gives above error. I checked the solution for "Invalid credentials" on https://github.com/plataformatec/devise/wiki/OmniAuth%3a-Overview and as mentioned there, my app is header set for App Type = Web. Not getting why it is not working.
Also my app is pending review from facebook. But i don't think it is related to this error. Following are the things i did for omniauth-facebook:
Gemfile contains:
gem "omniauth", "~> 1.1.4"
gem 'omniauth-facebook', '1.4.1'
In user model, added:
devise :omniauthable, :omniauth_providers => [:facebook]
attr_accessible :provider, :uid
def self.find_for_facebook_oauth(auth, signed_in_resource=nil)
user = User.where(:provider => auth.provider, :uid => auth.uid).first
unless user
user = User.create(name:auth.extra.raw_info.name,
provider:auth.provider,
uid:auth.uid,
email:auth.info.email,
password:Devise.friendly_token[0,20]
)
end
user
end
devise.rb
require "omniauth-facebook"
config.omniauth :facebook, "APP_ID", "APP_SECRET", :scope => "offline_access, email"
omniauth.rb:
OmniAuth.config.logger = Rails.logger
Rails.application.config.middleware.use OmniAuth::Builder do
provider :facebook, ENV['FACEBOOK_KEY'], ENV['FACEBOOK_SECRET'], {:provider_ignores_state => true}
end
route.rb:
devise_for :user, :controllers => { :omniauth_callbacks => "omniauth_callbacks" }
Omniauth controller:
class Users::OmniauthCallbacksController < Devise::OmniauthCallbacksController
def facebook
#user = User.find_for_facebook_oauth(request.env["omniauth.auth"], current_user)
if #user.persisted?
sign_in_and_redirect #user, :event => :authentication #this will throw if #user is not activated
set_flash_message(:notice, :success, :kind => "Facebook") if is_navigational_format?
else
session["devise.facebook_data"] = request.env["omniauth.auth"]
redirect_to new_user_registration_url
end
end
end
Can anybody help in this?

Thought I'd chip in here since this came up for me when trying to search for a solution for Could not authenticate you from Facebook because “Invalid credentials”
The problem is with Facebook API version >=2.3 you need to set {token_params: {parse: :json}} to your provider config.
devise.rb
config.omniauth :facebook,
APP_ID,
APP_SECRET,
token_params: { parse: :json } # <----- this line is NB
Answer found on this issue for omniauth-oauth2
UPDATE Aug 2018: The "invalid credentials" issue reoccurred, I had to remove the token_params setting for it to work again - so this may not be an issue anymore

Got it working!
My routes.rb and user.rb were wrong. And changed omniauth.rb too! Here are the previous and after files:
My routes.rb was:
devise_for :user, controllers: { registration: "registration" }
devise_for :user, controllers: { omniauth_callbacks: "omniauth_callbacks" }
So it was calling devise twice. I changed it to:
devise_for :user, controller: { registration: "registration", omniauth_callbacks: "omniauth_callbacks" }
Changed my omniauth.rb from this:
OmniAuth.config.logger = Rails.logger
Rails.application.config.middleware.use OmniAuth::Builder do
provider :facebook, ENV['FACEBOOK_KEY'], ENV['FACEBOOK_SECRET'], provider_ignores_state: true
end
to this:
OmniAuth.config.logger = Rails.logger
Also, i defined method def self.find_for_facebook_oauth(auth, signed_in_resource=nil) outside user.rb model (major mistake).
So got it working perfectly now :-)
Hope this helps someone.

Got it working too :)
We don't need to add this code in omniauth.rb
Rails.application.config.middleware.use OmniAuth::Builder do
provider :facebook, ENV['FACEBOOK_KEY'], ENV['FACEBOOK_SECRET']
end
if we already declare it in devise.rb
require "omniauth-facebook"
config.omniauth :facebook, "APP_ID", "APP_SECRET"

It helped me to solve a similar problem:
Note: v2.0.1 has an issue with callback url error. You need to add a callback url on config.
config.omniauth :facebook, "APP_ID", "APP_SECRET",
callback_url: "CALLBACK_URL"
https://github.com/plataformatec/devise/wiki/OmniAuth%3a-Overview

Upgrading gem to 4.0.0 and adding require "omniauth-facebook" to devise.rb fixed this for me.

I stack with this problem and no one advice was help me.
Problem was in redirect_uri. Devise omniauth gems generated it without https.
Finally resolved this by two steps:
Add force_ssl for rails.
Do not forget to add proxy_set_header X-Forwarded-Proto https; for nginx config, if you are using it.

Related

Ruby on Rails Tutorial NoMethodError in Users#index

I'm reading Michael Hartl's great "The Ruby on Rails Tutorial". And I faced a problem that wasn't described in the book.
I push a submit button on a Sign up page with blank fields, then, as it expected, the mistakes messages like these appears:
Name can't be blank
Email can't be blank
Email is invalid
Password can't be blank
But the URL changes from http://[::1]:3000/signup to http://[::1]:3000/users
Then I push the Chrome's refresh button and get redirecting to exactly http://[::1]:3000/users URL.
I understand that the pushing the submit button directs to .../users URL. How to change this route to the right one (still http://[::1]:3000/signup)?
Here's my users_controller.rb file
class UsersController < ApplicationController
before_action :logged_in_user, only: [:show, :edit, :update, :destroy]
before_action :correct_user, only: [:edit, :update]
before_action :admin_user, only: :destroy
def index
#users = User.where(activated: true).paginate(page: params[:page])
end
def show
#user = User.find(params[:id])
redirect_to root_url and return unless #user.activated?
#microposts = #user.microposts.paginate(page: params[:page])
end
def new
#user = User.new
end
def create
#user = User.new(user_params)
if #user.save
#user.send_activation_email
flash[:info] = "Please check your email to activate your account."
redirect_to root_url
else
render 'users/new', status: :unprocessable_entity
end
end
def edit
#user = User.find(params[:id])
end
end
Here's my routes.rb file
Rails.application.routes.draw do
get 'password_resets/new'
get 'password_resets/edit'
root 'static_pages#home'
get '/help', to: 'static_pages#help'
get '/about', to: 'static_pages#about'
get '/contact', to: 'static_pages#contact'
get '/signup', to: 'users#new'
get '/login', to: 'sessions#new'
post '/login', to: 'sessions#create'
delete '/logout', to: 'sessions#destroy'
default_url_options :host => "example.com"
resources :users
end
Thanks in advance!

Facebook redirects to sign up page after authenticating user Rails

I am intergrating Facebook login using device, and after allowing Facebook to get your info it redirects you to the sign up page. Here's my code:
class ApplicationController < ActionController::Base
protect_from_forgery with: :exception
before_action :authenticate_user!
before_action :configure_permitted_parameters, if: :devise_controller?
def configure_permitted_parameters
devise_parameter_sanitizer.permit(:sign_up, keys: [:first_name, :description, :photo ])
devise_parameter_sanitizer.permit(:account_update, keys: [:username, :first_name, :last_name, :description, :photo ])
end
end
Callback controller
class Users::OmniauthCallbacksController < Devise::OmniauthCallbacksController
def facebook
#user = User.from_omniauth(request.env["omniauth.auth"])
if #user.persisted?
sign_in_and_redirect #user, :event => :authentication #this will throw if #user is not activated
set_flash_message(:notice, :success, :kind => "Facebook") if is_navigational_format?
else
session["devise.facebook_data"] = request.env["omniauth.auth"]
redirect_to new_user_registration_url
end
end
def failure
redirect_to root_path
end
end
And my user model is
def self.new_with_session(params, session)
super.tap do |user|
if data = session["devise.facebook_data"] && session["devise.facebook_data"]["extra"]["raw_info"]
user.email = data["email"] if user.email.blank?
end
end
end
def self.from_omniauth(auth)
where(provider: auth.provider, uid: auth.uid).first_or_create do |user|
user.email = auth.info.email
user.password = Devise.friendly_token[0,20]
user.first_name = auth.info.name # assuming the user model has a name
user.image = auth.info.image # assuming the user model has an image
end
end
I'd really appreciate an extra eye on what I'm doing wrong, or where I am missing something. Thanks!
You need to add this column for provider and uid to your users table, i think rails can't match your user :
rails g migration add_provider_and_uid_to_users provider:string uid: string
And try to write me the rails server response it Can help to figure out the bug source

google-api-client suddenly comes back with "invalid request"

I've been running Ruby scripts for weeks now using a Service Account, but today I'm getting an "Invalid Request" when I try to build the client using the following function:
def build_client(user_email)
client = Google::APIClient.new
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/calendar',
:issuer => SERVICE_ACCOUNT_EMAIL,
:signing_key => Google::APIClient::KeyUtils.load_from_pkcs12(SERVICE_ACCOUNT_PKCS12_FILE_PATH, "notasecret"),
:person => user_email
)
client.authorization.fetch_access_token!
return client
end
Is there a lifespan on Service Accounts? I tried creating another Service Account and using that but I get the same result:
Authorization failed. Server message: (Signet::AuthorizationError)
{
"error" : "invalid_request"
}
Stumped!
OK. I figured it out. It was all to do with the user_email. I was reading it from a file and forgot to chomp the linefeed off, so it was objecting to a mal-formed email address.

Setting env when using rspec to test omniauth callbacks

I'm having a strange problem when trying to set a callback for Facebook Authentication via Omniauth. In my controller (simplified to just the code necessary to show the error) I have:
class Users::OmniauthCallbacksController < Devise::OmniauthCallbacksController
def facebook
raise env.inspect
# auth_hash = env["omniauth.auth"]
end
end
this works in production mode, showing me the hash. However in test mode env is set to nil.
I have the following set in my spec_helper.rb file
OmniAuth.config.test_mode = true
OmniAuth.config.add_mock(:facebook, {"credentials" => {
"token" => "foo-token"
}
})
and my spec looks like this:
require 'spec_helper'
describe Users::OmniauthCallbacksController do
describe "Facebook" do
before(:each) do
request.env["devise.mapping"] = Devise.mappings[:user]
request.env["omniauth.auth"] = OmniAuth.config.mock_auth[:facebook]
end
it "should be a redirect" do
get :facebook
response.should redirect_to(root_path)
end
end
end
Can anyone enlighten me on what I need to do to have env not be nil when running my tests?
I use the following in my spec_helper.rb :
RACK_ENV = ENV['ENVIRONMENT'] ||= 'test'
I don't use Rails or Devise though so YMMV. I've also seen various threads saying that someone had to do this before their requires to get it to work.

Redirected to http://localhost:3000/session/new

So I have a rails app 2.x app that works fine via the web, but when trying to perform a POST I keep getting "Redirected to http://localhost:3000/session/new Filter chain halted as [:require_user] rendered_or_redirected.". In my iPhone app, I can create a new session and sign-in via my iPhone app, but cannot POST to say the POSTS_Controller.
I have this in my code
Posts_Controller
before_filter :require_user, :only => [:create, :update, :destroy]
Application_Controller
# Filters added to this controller apply to all controllers in the application.
# Likewise, all the methods added will be available for all controllers.
class ApplicationController < ActionController::Base
include AuthenticatedSystem
include Geokit::Geocoders
helper :all # include all helpers, all the time
#session :session_key => '_cwa_session_id'
#filter_parameter_logging :password
# See ActionController::RequestForgeryProtection for details
# Uncomment the :secret if you're not using the cookie session store
protect_from_forgery # :secret => 'eejj7eded74769099999944a729b4f'
#filter_parameter_logging(:password)
before_filter :login_from_cookie
before_filter :find_user_interests
before_filter :find_user_posts
protected
def find_user_interests
#user_interests = cur_user ? cur_user.interesting_posts : []
logger.debug "User interests hash: #{current_user.inspect}"
end
def find_user_posts
#user_posts = cur_user ? cur_user.posts : []
end
def cur_user
User.find(session[:user_id]) if session[:user_id]
end
def require_user
unless cur_user
flash[:error] = "You must be logged in to do that."
redirect_to '/session/new'
return false
end
end
geocode_ip_address
def geokit
#location = session[:geo_location]
end
end
I have been working on this for 2 months and cannot figure out the issue. In my iPhone app I am using ObjectiveResource. I am sending over json and have "Mime::Type.register_alias "application/json", :json" set up on the rails side.
I am not a rails developer, but the before filter for require_user is unable to pass the cur_user test in that is cannot find :user_id in the session hash. Are you sure that you have a session that persists when using the iPhone? Are you using devise for authentication? Just for kicks, does it work if you manually pass the user_id as params?