Hello everyone,
This week, I will be writing about how to setup Facebook authentication for your Rails app.
Prerequisites
- An app using Rails 6 with devise setup for authentication
- A working knowledge of creating a new Rails app
- A working knowledge of devise for authentication
- An active Facebook account
Facebook Authentication
To implement Facebook auth, we need to create an app on Facebook that will generate an APP_ID
and APP_SECRET
for setting up devise omniauth later.
Create Facebook app
- Go to https://developers.facebook.com/
- Click on
My Apps
in the navbar - Click on
Add a new App
- On the modal that pops up, select the
For Everything Else
option. - Next, add your
App Display Name
and click theCreate App Id
button - Complete the security check and this should redirect you to the app
- On the sidebar, click on
Setting
and then click onBasic
. You should be able to see yourAPP_ID
andAPP_SECRET
. Copy and save for later. - In the
App domains
, addlocalhost
. You can also add your add icon if you have one. - Scroll down to the end of the page and click on the
Add Platform
- On the modal that pops up, select
Website
- Add
http://localhost
- Save your changes
Setup Facebook Auth in devise
In this section, we will be setting up facebook auth in our rails app.
- Add the omniauth-facebook gem to your gemfile
gem 'omniauth-facebook'
- Run
bundle install
- Next we create a migration to add provider and uid to the user model. This stores the provider the user uses to register whether its
facebook
orgoogle
.
$ rails g migration AddOmniauthToUsers provider:string uid:string
- Run
rake db:migrate
- Next, we need to update the devise initializer file to include the
APP_ID
andAPP_SECRET
we saved for later
# config/initializers/devise.rb
config.omniauth :facebook, "APP_ID", "APP_SECRET"
Note: If you chose to use the credentials to save your environment variables. You can use this command to edit it in your code editor. Run this code in your terminal. Change code
part to your code editor if you don't use vscode.
$ `EDITOR="code --wait" bin/rails credentials:edit`
In the decrypted credential file, add the app_id and app_secret
facebook:
APP_ID: '<facebook_app_id>'
APP_SECRET: '<facebook_app_secret>'
So your initializer file update will be
config.omniauth :facebook, Rails.application.credentials.facebook[:APP_ID], Rails.application.credentials.facebook[:APP_SECRET], token_params: { parse: :json }
- Next we need to make the user model omniauthable. Add this to the user model
# app/models/user.rb
devise :omniauthable, omniauth_providers: %i[facebook]
- Next, we create an omniauth controller in a user folder to respond to facebook authentication.
# 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"].except(:extra) # Removing extra as it can overflow some session stores
redirect_to new_user_registration_url
end
end
def failure
redirect_to root_path
end
end
- Next, we go back to the
user
model to add thefrom_omniauth
self method. This method finds or creates a new user when they register. The name_split part of for those that store the first_name and last_name of their users.
# app/models/user.rb
def self.from_omniauth(auth)
name_split = auth.info.name.split(" ")
user = User.where(email: auth.info.email).first
user ||= User.create!(provider: auth.provider, uid: auth.uid, last_name: name_split[0], first_name: name_split[1], email: auth.info.email, password: Devise.friendly_token[0, 20])
user
end
- Next, we update the routes file for include the new controller we just added
# config/routes.rb
devise_for :users, controllers: { omniauth_callbacks: 'users/omniauth_callbacks' }
- Finally, we add the facebook button to our view using a facebook path provided by devise. You can use this same path for both registration and login. You just need to update the button description.
<%= link_to "Register with Facebook", user_facebook_omniauth_authorize_path %>
And that should add facebook auth to your app.
Other Authentication
The process is quite similar for google authentication. We need to create a project for the app and then create the credentials for auth. I am going to attach a link to create credentials for google auth and the omniauth-google gem.
Create credentials on google
Omniauth Google gem
Omniauth twitter gem
Twitter guide for creating an app
Let me know what you think and what to write about in the comment section.
Until next week
Top comments (10)
Nice article Mbonu, such a coincidence BTW :-)
@joshpuetz has been working on adding optional Facebook authentication support to Forems in the following PR:
Log in with Facebook #9922
What type of PR is this? (check all applicable)
Description
Adds support to logging into Forem with Facebook Oauth. We're only using the Omniauth Facebook provider, not Facebook's SDK. In addition: only the bare minimum amount of information is requested from Facebook, so no app review is required on their end (and we limit the amount of user data that we're asking for). Included is:
Authentication::Provider
subclassuser
Related Tickets & Documents
resolves github.com/forem/InternalProjectPl...
QA Instructions, Screenshots, Recordings
Added tests?
Added to documentation?
[optional] Are there any post deployment tasks we need to perform?
[optional] What gif best describes this PR or how it makes you feel?
The main difference in our approach is that we have a "one to many" correspondence between a user and the preferred login method. Something we call
Identity
. Thus a user can have a Twitter identity, a GitHub identity and so on.I had some problems with this, I have to add SSL to my localhost app so it works with FB but it says the url is not part of the config I don't understand since I'm in localhost:3000 and I have added localhost as part of the domains as well as added the url localhost:3000 in Facebook
Thanks Blessing for this helpful article, If you are getting this Error: Not found. Authentication passthru after following this guide, there is a fix for it in this github issue: github.com/heartcombo/devise/issue...
Not found. Authentication passthru.
How can a solve this error?
I used gem
"omniauth", "~> 1.9.1"
in Gemfile instead of newer version !After using your code for Facebook authentication, this happens every time.
Will you help me, I am new to Rails.
Not found. Authentication passthru.
What is %i[facebook] ? is the %i a mistake?
no, %i is the non-interpolated Array of symbols, separated by whitespace.
%i[facebook] same as [:facebook].
source: stackoverflow.com/a/47039746/4919728
I get:
The action 'facebook' could not be found for Devise::OmniauthCallbacksController
any ideas?
I found that is caused by the controller for
:omniauth_callbacks
in devise route is not specified. I solved it by specify:omniauth_callbacks
controller to the new controller I created based on this article (Users::OmniauthCallbacksController
).