Skip to content

Instantly share code, notes, and snippets.

@schleg
Created May 26, 2011 17:26
Show Gist options
  • Save schleg/993566 to your computer and use it in GitHub Desktop.
Save schleg/993566 to your computer and use it in GitHub Desktop.
Setup for Devise + Omniauth
gem 'pg'
group :development do
gem 'ruby-debug'
end
gem 'rake', '~> 0.8.7'
gem 'devise'
gem 'oa-oauth', :require => 'omniauth/oauth'
gem 'omniauth'
gem 'haml'
gem 'dynamic_form'
gem 'sass'
gem 'jquery-rails'
gem 'cancan'
gem 'uuidtools'
rails generate devise:install
rails generate devise user
rails g migration add_name_to_users name:string
rails g model authorization provider:string uid:string user_id:integer token:string secret:string name:string link:string
# /db/migrate/<timestamp>_devise_create_users.rb
class DeviseCreateUsers < ActiveRecord::Migration
def self.up
create_table(:users) do |t|
t.database_authenticatable :null => false
t.recoverable
t.rememberable
t.trackable
t.encryptable
t.confirmable
t.lockable :lock_strategy => :failed_attempts, :unlock_strategy => :both
t.token_authenticatable
t.timestamps
end
add_index :users, :email, :unique => true
add_index :users, :reset_password_token, :unique => true
add_index :users, :confirmation_token, :unique => true
add_index :users, :unlock_token, :unique => true
add_index :users, :authentication_token, :unique => true
end
def self.down
drop_table :users
end
end
# app/models/authorization.rb
class Authorization < ActiveRecord::Base
belongs_to :user
end
# config/environments
config.action_mailer.perform_deliveries = true
config.action_mailer.raise_delivery_errors = true
config.action_mailer.default_url_options = { :host => 'localhost:3000' }
HOST = 'localhost:3000'
ADMIN_EMAIL_FROM = ""
PONY_VIA_OPTIONS = {
:address => 'smtp.gmail.com',
:port => '587',
:enable_starttls_auto => true,
:user_name => '',
:password => '',
:authentication => :plain,
:domain => "localhost.localdomain" }
# app/config/initializers/devise.rb
Devise.setup do |config|
...
config.sign_out_via = :get
...
config.omniauth :facebook, "KEY", "SECRET"
config.omniauth :twitter, "KEY", "SECRET"
config.omniauth :linked_in, "KEY", "SECRET"
...
end
class Users::OmniauthCallbacksController < Devise::OmniauthCallbacksController
require 'uuidtools'
def facebook
oauthorize "Facebook"
end
def twitter
oauthorize "Twitter"
end
def linked_in
oauthorize "LinkedIn"
end
def passthru
render :file => "#{Rails.root}/public/404.html", :status => 404, :layout => false
end
private
def oauthorize(kind)
@user = find_for_ouath(kind, env["omniauth.auth"], current_user)
if @user
flash[:notice] = I18n.t "devise.omniauth_callbacks.success", :kind => kind
session["devise.#{kind.downcase}_data"] = env["omniauth.auth"]
sign_in_and_redirect @user, :event => :authentication
end
end
def find_for_ouath(provider, access_token, resource=nil)
user, email, name, uid, auth_attr = nil, nil, nil, {}
case provider
when "Facebook"
uid = access_token['uid']
email = access_token['extra']['user_hash']['email']
auth_attr = { :uid => uid, :token => access_token['credentials']['token'], :secret => nil, :name => access_token['extra']['user_hash']['name'], :link => access_token['extra']['user_hash']['link'] }
when "Twitter"
uid = access_token['extra']['user_hash']['id']
name = access_token['user_info']['name']
auth_attr = { :uid => uid, :token => access_token['credentials']['token'], :secret => access_token['credentials']['secret'], :name => name, :link => "http://twitter.com/#{name}" }
when 'LinkedIn'
uid = access_token['uid']
name = access_token['user_info']['name']
auth_attr = { :uid => uid, :token => access_token['credentials']['token'], :secret => access_token['credentials']['secret'], :name => name, :link => access_token['user_info']['public_profile_url'] }
else
raise 'Provider #{provider} not handled'
end
if resource.nil?
if email
user = find_for_oauth_by_email(email, resource)
elsif uid && name
user = find_for_oauth_by_uid(uid, resource)
if user.nil?
user = find_for_oauth_by_name(name, resource)
end
end
else
user = resource
end
auth = user.authorizations.find_by_provider(provider)
if auth.nil?
auth = user.authorizations.build(:provider => provider)
user.authorizations << auth
end
auth.update_attributes auth_attr
return user
end
def find_for_oauth_by_uid(uid, resource=nil)
user = nil
if auth = Authorization.find_by_uid(uid.to_s)
user = auth.user
end
return user
end
def find_for_oauth_by_email(email, resource=nil)
if user = User.find_by_email(email)
user
else
user = User.new(:email => email, :password => Devise.friendly_token[0,20])
user.save
end
return user
end
def find_for_oauth_by_name(name, resource=nil)
if user = User.find_by_name(name)
user
else
user = User.new(:name => name, :password => Devise.friendly_token[0,20], :email => "#{UUIDTools::UUID.random_create}@host")
user.save false
end
return user
end
end
class RegistrationsController < Devise::RegistrationsController
def update
if params[resource_name][:password].blank?
params[resource_name].delete(:password)
params[resource_name].delete(:password_confirmation) if params[resource_name][:password_confirmation].blank?
end
# Override Devise to use update_attributes instead of update_with_password.
# This is the only change we make.
if resource.update_attributes(params[resource_name])
set_flash_message :notice, :updated
# Line below required if using Devise >= 1.2.0
sign_in resource_name, resource, :bypass => true
redirect_to after_update_path_for(resource)
else
clean_up_passwords(resource)
render_with_scope :edit
end
end
end
devise_for :users, :path => "accounts", :controllers => { :omniauth_callbacks => "users/omniauth_callbacks", :registrations => "registrations" }
# app/models/user.rb
class User < ActiveRecord::Base
devise :database_authenticatable, :registerable, :recoverable, :rememberable, :trackable, :validatable, :confirmable, :omniauthable
attr_accessible :email, :name, :password, :password_confirmation, :remember_me
has_many :authorizations, :dependent => :destroy
end
@seanaedmiston
Copy link

I searched long and hard for a good multi-provider example of Devise with Omniauth (using Devise's omniauthable). Great to have finally found one.!!

@schleg
Copy link
Author

schleg commented Aug 9, 2011 via email

@ovargas27
Copy link

If you try this code in rails 3.1 you need to change file omniauth_callbacks_controller.rb line 95 from

user.save false

to

user.save :validate => false

@joshed-io
Copy link

Very awesome. Quick tip - as of now you'll need to specify the omniauth gem version explicitly as the 1.0 is incompatible with devise at the moment.

gem 'omniauth', '0.3.2'

See omniauth/omniauth#496 for more info.

Also FWIW :lockable is in the migration but not on the User model.

@cielo
Copy link

cielo commented Jan 13, 2012

This is for omniauth with version < 1.0. For those of you who wants to use new omniauth 1.0 with devise, follow strategies on

https://github.com/intridea/omniauth/wiki/List-of-Strategies

@jimjh
Copy link

jimjh commented Jan 3, 2013

Line 27: session["devise.#{kind.downcase}_data"] = env["omniauth.auth"]
Line 28: sign_in_and_redirect @user, :event => :authentication

Line 27 should go after Line 28, because Devise resets the session when the user is signed in.

@colindean
Copy link

The migration provided here won't work on Devise 2.0+. See https://github.com/plataformatec/devise/wiki/How-To:-Upgrade-to-Devise-2.0-migration-schema-style for details on how to upgrade. I think this tut might be a little outdated from the get-go.

@colindean
Copy link

user.rb:5 needs also to have :omniauth_providers => [:facebook, :twitter, :gplus] and etc. in the devise line in the model.

@benjiwheeler
Copy link

Do you really want rememberable and database_authenticatable? do those make sense to use with omniauth?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment