I'm stuck with integrating devise
with omniauth-facebook
My demo app is using:
I followed the following guide on the Wiki page: https://github.com/plataformatec/devise/wiki/OmniAuth:-Overview but having problems creating the user.
It will sign-in the user and add the app to the user's Facebook (in App Settings) but it does register the account to the User
model.
# Gemfile
source 'https://rubygems.org'
gem 'rails', '~> 5.0.0'
gem 'devise'
gem 'pundit'
gem 'omniauth-facebook'
# Gemfile.lock for the 3 authorization and authentication gems
GEM
remote: https://rubygems.org/
remote: https://rails-assets.org/
specs:
devise (4.2.0)
bcrypt (~> 3.0)
orm_adapter (~> 0.1)
railties (>= 4.1.0, < 5.1)
responders
warden (~> 1.2.3)
pundit (1.1.0)
omniauth (1.3.1)
hashie (>= 1.2, < 4)
rack (>= 1.0, < 3)
omniauth-facebook (4.0.0)
omniauth-oauth2 (~> 1.2)
omniauth-oauth2 (1.4.0)
oauth2 (~> 1.0)
omniauth (~> 1.2)
The schema for the User model.
I added a migration provider:string
and uid:string
# == Schema Information
#
# Table name: users
#
# id :integer not null, primary key
# email :string default(""), not null
# encrypted_password :string default(""), not null
# reset_password_token :string
# reset_password_sent_at :datetime
# remember_created_at :datetime
# sign_in_count :integer default(0), not null
# current_sign_in_at :datetime
# last_sign_in_at :datetime
# current_sign_in_ip :inet
# last_sign_in_ip :inet
# created_at :datetime not null
# updated_at :datetime not null
# name :string default(""), not null
# provider :string
# uid :string
The ApplicationController
contains pundit
and devise
code:
class ApplicationController < ActionController::Base
include Pundit
rescue_from Pundit::NotAuthorizedError, with: :user_not_authorized
protect_from_forgery with: :exception
before_action :configure_permitted_parameters, if: :devise_controller?
private
def user_not_authorized
flash[:error] = "You are not authorized to perform this action."
redirect_to(request.referrer || root_path)
end
protected
def configure_permitted_parameters
devise_parameter_sanitizer.permit(:sign_up, keys: [:name])
devise_parameter_sanitizer.permit(:account_update, keys: [:name])
end
end
I've configured config/initializers/devise.rb
to include :facebook
in the omniauth
config.
# File: config/initializers/devise.rb
# Use this hook to configure devise mailer, warden hooks and so forth.
# Many of these configuration options can be set straight in your model.
Devise.setup do |config|
require 'devise/orm/active_record'
config.case_insensitive_keys = [:email]
config.strip_whitespace_keys = [:email]
config.skip_session_storage = [:http_auth]
config.stretches = Rails.env.test? ? 1 : 11
config.reconfirmable = true
config.password_length = 6..128
config.email_regexp = /\A[^@\s]+@[^@\s]+\z/
config.sign_out_via = :delete
# ==> OmniAuth
# Add a new OmniAuth provider. Check the wiki for more information on setting
# up on your models and hooks.
# config.omniauth :github, 'APP_ID', 'APP_SECRET', scope: 'user,public_repo'
config.omniauth :facebook, ENV['FACEBOOK_APP_ID'], ENV['FACEBOOK_APP_SECRET'], callback_url: ENV['FACEBOOK_CALLBACK_URL'], scope: 'email', info_fields: 'email,name'
end
I've added omniauthable
to the User
model.
class User < ApplicationRecord
# Include default devise modules. Others available are:
# :confirmable, :lockable, :timeoutable and :omniauthable
devise :database_authenticatable, :registerable,
:recoverable, :rememberable, :trackable, :validatable,
:omniauthable, omniauth_providers: [:facebook]
def self.from_omniauth(auth)
where(provider: auth.provider, uid: auth.uid).first_or_create do |user|
user.name = auth.info.name
user.email = auth.info.email
user.password = Devise.friendly_token[0,20]
end
end
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
end
I've created an OmniauthCallbacksController
to handle sign-in requests.
# File: app/controllers/users/omniauth_callbacks_controller.rb
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
In the Routes
I've added the following:
# File: config/routes.rb
Rails.application.routes.draw do
devise_for :users, controllers: { omniauth_callbacks: "users/omniauth_callbacks" }
root 'pages#index'
end
Added "Sign in with Facebook" link to devise
sessions#new
view.
# File: app/views/devise/sessions/new.html.erb
<div class="login">
<%= link_to "Sign in with Facebook", user_facebook_omniauth_authorize_path %>
# This is the link it creates: <a href="/users/auth/facebook">Sign in with Facebook</a>
</div>
code
and state
(check *NB*NB Return url from Facebook:
http://localhost:3000/?code=REALLYLONGHASHOFCHARACTERS&state=ANOTHERSETOFREALLYLONGHASHOFCHARACTERS
The development.log show:
Started GET "/users/auth/facebook" for ::1 at 2016-08-10 18:43:26 +1000
I, [2016-08-10T18:43:26.084371 #2292] INFO -- omniauth: (facebook) Request phase initiated.
Started GET "/users/auth/facebook" for ::1 at 2016-08-10 18:43:26 +1000
I, [2016-08-10T18:43:26.521627 #2292] INFO -- omniauth: (facebook) Request phase initiated.
Started GET "/?code=REALLYLONGHASHOFCHARACTERS&state=ANOTHERSETOFREALLYLONGHASHOFCHARACTERS" for ::1 at 2016-08-10 18:44:19 +1000
Processing by ListingsController#index as HTML
Parameters: {"code"=>"REALLYLONGHASHOFCHARACTERS", "state"=>"ANOTHERSETOFREALLYLONGHASHOFCHARACTERS"}
I don't think it's hitting Users::OmniauthCallbacksController < Devise::OmniauthCallbacksController
because I put a raise "Error"
on the facebook
action but it doesn't raise any errors. And I can't see the omniauth_callbacks: "users/omniauth_callbacks"
when running Rails routes
Checking the routes show:
# Routes
|| Prefix Verb URI Pattern Controller#Action
|| new_user_session GET /users/sign_in(.:format) devise/sessions#new
|| user_session POST /users/sign_in(.:format) devise/sessions#create
|| destroy_user_session DELETE /users/sign_out(.:format) devise/sessions#destroy
|| user_facebook_omniauth_authorize GET|POST /users/auth/facebook(.:format) users/omniauth_callbacks#passthru
|| user_facebook_omniauth_callback GET|POST /users/auth/facebook/callback(.:format) users/omniauth_callbacks#facebook
|| user_password POST /users/password(.:format) devise/passwords#create
|| new_user_password GET /users/password/new(.:format) devise/passwords#new
|| edit_user_password GET /users/password/edit(.:format) devise/passwords#edit
|| PATCH /users/password(.:format) devise/passwords#update
|| PUT /users/password(.:format) devise/passwords#update
|| cancel_user_registration GET /users/cancel(.:format) devise/registrations#cancel
|| user_registration POST /users(.:format) devise/registrations#create
|| new_user_registration GET /users/sign_up(.:format) devise/registrations#new
|| edit_user_registration GET /users/edit(.:format) devise/registrations#edit
|| PATCH /users(.:format) devise/registrations#update
|| PUT /users(.:format) devise/registrations#update
|| DELETE /users(.:format) devise/registrations#destroy
|| root GET / pages#index
I'm not sure what to do from here. Any help and insight is much appreciated.
All working now.
It has to do with the incorrect callback_url
.
From the logs:
Started GET "/users/auth/facebook" for ::1 at 2016-08-10 18:43:26 +1000
I, [2016-08-10T18:43:26.084371 #2292] INFO -- omniauth: (facebook) Request phase initiated.
Started GET "/users/auth/facebook" for ::1 at 2016-08-10 18:43:26 +1000
I, [2016-08-10T18:43:26.521627 #2292] INFO -- omniauth: (facebook) Request phase initiated.
Started GET "/?code=REALLYLONGHASHOFCHARACTERS&state=ANOTHERSETOFREALLYLONGHASHOFCHARACTERS" for ::1 at 2016-08-10 18:44:19 +1000
The last line of the log file shows it's not going to the correct url:
Started GET "/?code=REALLYLONGHASHOFCHARACTERS&state=ANOTHERSETOFREALLYLONGHASHOFCHARACTERS" for ::1 at 2016-08-10 18:44:19 +1000
The initializer config shows:
config.omniauth :facebook,
ENV['FACEBOOK_APP_ID'],
ENV['FACEBOOK_APP_SECRET'],
callback_url: ENV['FACEBOOK_CALLBACK_URL'],
scope: 'email', info_fields: 'email,name'
The callback_url
was http://localhost:3000
which is incorrect.
I changed the callback_url
from http://localhost:3000
to http://localhost:3000/users/auth/facebook/callback
It is now working and I hope this helps someone in the future.