I'm building a web app with Ruby on Rails and I want my users to authenticate and aggregate data from Linked In (and others like Github, Twitter, etc...).
I am using these gems:
Devise for registration
omniauth-linkedin for authentication
pengwynn/linkedin for data aggregation
Though, Linked In has a not-so-nice pin thing.
Is there a way to avoid it and get the data I want from my users account without having them to go to linked in, fetch a pin and submit it to me?
Thanks in advance.
authentications_controller.rb
class AuthenticationsController < ApplicationController
def index
#authentications = current_user.authentications if current_user
end
def create
omniauth = request.env["omniauth.auth"]
authentication = Authentication.
find_by_provider_and_uid(omniauth['provider'], omniauth['uid'])
if authentication
flash[:notice] = "Signed in successfully."
sign_in_and_redirect(:user, authentication.user)
elsif current_user
current_user.authentications.
create!(provider: omniauth['provider'], uid: omniauth['uid'])
current_user.apply_omniauth(omniauth)
flash[:notice] = "Authentication successful."
redirect_to authentications_url
else
user = User.new
user.apply_omniauth(omniauth)
if user.save
flash[:notice] = "Signed in successfully."
sign_in(:user, user)
redirect_to user_path(user.username)
else
session[:omniauth] = omniauth.except('extra')
redirect_to new_user_registration_url
end
end
end
Related
So far i have managed to login users with google plus using the omniauth-google-oauth2 gem.
As far as i am concerned you get an access token that expires at some time. How can i refresh that token from the google API lets say once a week if the user logins with google plus on my website in a week from now?
below is the code i have in my sessioncontroller.rb
def google_oauth2
auth_hash = request.env['omniauth.auth']
#identity = Identity.find_by_provider_and_uid(auth_hash["provider"], auth_hash["uid"])
if #identity
log_in #identity.user
flash[:success] = "Welcome, #{#identity.user.name}!"
else
random_password = SecureRandom.urlsafe_base64(n=6)
##user = create_with_omniauth(auth_hash)
#user = User.new(
name:auth_hash['info']['name'],
email:auth_hash['info']['email'],
password:random_password,
password_confirmation:random_password,
activated:true
)
#user.identities.build(
uid: auth_hash['uid'],
provider: auth_hash['provider'],
image_url: auth_hash['info']['image'],
oauth_token: auth_hash['credentials']['token'],
oauth_refresh_token: auth_hash['credentials']['refresh_token'],
oauth_expires_at: auth_hash['credentials']['expires_at']
)
if #user.save!
log_in #user
flash[:success] = "Hello, #{#user.name}! An account has been created for you!"
else
flash[:warning] = "There was an error while trying to authenticate you..."
end
end
redirect_to root_path
end
some attributes are saved in user table and some in Identity table with a has_many identities, belongs to user model because in the future i want to add multiple providers.
I am working with omniauth with Rails and trying to get twitter, facebook and google hooked up for authentication but keep running into this error:
PG::Error: ERROR: duplicate key value violates unique constraint "index_users_on_email"
DETAIL: Key (email)=() already exists.
Here is my Authentication Controller:
class AuthorizationsController < ApplicationController
def create
authentication = Authorization.find_by_provider_and_uid(auth['provider'], auth['uid'])
if authentication
flash[:notice] = "Signed In Successfully"
sign_in authentication.user, event: :authentication
redirect_to root_path
else
athlete = Athlete.new
athlete.apply_omniauth(auth)
debugger
if athlete.save(validate: false)
flash[:notice] = "Account created and signed in successfully"
sign_in athlete, event: :authentication
redirect_to finalize_profile_path
else
flash[:error] = "An error has occurred. Please try again."
redirect_to root_path
end
end
end
def failure
render json: params.to_json
end
private
def auth
request.env["omniauth.auth"]
end
def resource(user_type)
user_type.downcase.to_sym
end
end
I think what is happening is that when the Athlete is created it is creating one with a blank email address and the unique key is failing... how could I get around this? I think I know how to fix this for Google integration but since Twitter doesn't return an email, this issue will not resolve itself
This is how I was able to get it working:
class AuthorizationsController < ApplicationController
def create
authentication = Authorization.find_by_provider_and_uid(auth['provider'], auth['uid'])
if authentication
flash[:notice] = "Signed In Successfully"
sign_in authentication.user, event: :authentication
redirect_to root_path
else
athlete = Athlete.new(email: generate_auth_email(params[:provider]) )
athlete.apply_omniauth(auth)
debugger
if athlete.save(validate: false)
flash[:notice] = "Account created and signed in successfully"
sign_in athlete, event: :authentication
redirect_to finalize_profile_path
else
flash[:error] = "An error has occurred. Please try again."
redirect_to root_path
end
end
end
def failure
render json: params.to_json
end
private
def auth
request.env["omniauth.auth"]
end
def resource(user_type)
user_type.downcase.to_sym
end
def generate_auth_email(provider)
return auth.info.try(:email) unless provider == "twitter"
return "#{auth.uid}#twitter.com" if provider == "twitter"
end
end
I create an email using the twitter uid with twitter.com being the domain since twitter does not return an email address
Hope this helps someone in the future
I'm trying to integrate Devise with Omniauth and have some troubles with them both. The main problem is to bind Devise User model with Omniauth authentications. I want a simple way to associate my user, with external providers like facebook, twitter, g+ and so on.
One of the most annoying issues that arise with my application is:
If an user registered on my site with devise (I call it local user), that means, provided an email and a password, when user tries to login with twitter, the system asks for mail confirmation. If that mail already exists, then user have to provide another mail. I want instead that he can confirm with a password that it is actually his email. How to do that? How can I override that template?
This is my authentications controller:
class AuthenticationsController < ApplicationController
def index
#authentications = Authentication.all
end
def create
#authentication = Authentication.new(params[:authentication])
if #authentication.save
redirect_to authentications_url, :notice => "Successfully created authentication."
else
render :action => 'new'
end
end
def destroy
#authentication = Authentication.find(params[:id])
#authentication.destroy
redirect_to authentications_url, :notice => "Successfully destroyed authentication."
end
def twitter
omni = request.env["omniauth.auth"]
authentication = Authentication.find_by_provider_and_uid(omni['provider'], omni['uid'])
if authentication
flash[:notice] = "Logged in Successfully"
sign_in_and_redirect User.find(authentication.user_id)
elsif current_user
token = omni['credentials'].token
token_secret = omni['credentials'].secret
current_user.authentications.create!(:provider => omni['provider'], :uid => omni['uid'], :token => token, :token_secret => token_secret)
flash[:notice] = "Authentication successful."
sign_in_and_redirect current_user
else
user = User.new
user.apply_omniauth(omni)
if user.save
flash[:notice] = "Logged in."
sign_in_and_redirect User.find(user.id)
else
session[:omniauth] = omni.except('extra')
p session
redirect_to new_user_registration_path
end
end
end
end
I also have no idea where new_users_registration_path is.
If i use omniauth for twitter verification.. code for the following is
def create
user = User.from_omniauth(env["omniauth.auth"])
session[:user_id] = user.id
redirect_to root_url, notice: "Successfully signed in"
end
but if i use omniauth+devise for twitter verificaiton.. code for the following is
def twitter
omni= request.env["omniauth.auth"]
authentication = Authentication.find_by_provider_and_uid(omni['provider'],omni['uid'])
if authentication
flash[:notice]="Logged in successfully"
sign_in_and_redirect User.find(authentication.user_id)
elsif current_user
token=omni['credentials'].token
token_secret=omni['credentials'].secret
current_user.authentications.create! (:provider=>omni['provider'],:uid=>omni['uid'],:token=>token,:token_secret=>token_secret)
flash[:notice]="Authentication successful."
sign_in_and_redirect current_user
else
user=User.new
user.apply_omniauth(omni)
if user.save
flash[:notice]="Logged in."
sign_in_and_redirect User.find(user.id)
else
session[:omniauth]=omni.except('extra')
redirect_to new_user_registration_path
end
end
end
Which one is better Omniauth or Omniauth+Devise?
Devise will give you certain ready made helper functions like current_user, user_signed_in? and controller filters like before :authenticate_user!.
Though they are very basic to implement on our own, but when omniauth-twitter alone, you will have to implement on your own.
If you don't plan to have very sophisticated user authentication and just want simple twitter based authentication, you can go ahead and use omniauth-twitter alone. Devise will open your application for mannual (form based) registrations by default, which you may not want.
I am using Devise with Omniauth to have users sign into my app with Facebook. I used the Railscast tutorials to get it up and running.
If a user is already a member of my site authenticating through facebook works fine. The problem comes in when authenticating a new user with facebook. When it goes to create a new user for my User model I get the "users.encrypted_password may not be NULL" error. I can't figure out how to pass over the password to the User model from Facebook information.
This is what I have:
authentations_controller.rb
class AuthenticationsController < ApplicationController
def index
#authentications = current_user.authentications if current_user
end
def create
omniauth = request.env["omniauth.auth"]
authentication = Authentication.find_by_provider_and_uid(omniauth['provider'], omniauth['uid'])
if authentication
flash[:notice] = "Signed in successfully."
sign_in_and_redirect(:user, authentication.user)
elsif current_user
current_user.authentications.create!(:provider => omniauth['provider'], :uid => omniauth['uid'])
flash[:notice] = "Authentication successful."
redirect_to authentications_url
else
user = User.new
user.apply_omniauth(omniauth)
if user.save
flash[:notice] = "Signed in successfully."
sign_in_and_redirect(:user, user)
else
session[:omniauth] = omniauth.except('extra')
redirect_to new_user_registration_url
end
end
end
user.rb
def apply_omniauth(omniauth)
self.email = omniauth['user_info']['email'] if email.blank?
authentications.build(:provider => omniauth['provider'], :uid => omniauth['uid'])
end
def password_required?
(authentications.empty? || !password.blank?) && super
end
Any help would be great, thanks in advance!
Add :password => Devise.friendly_token[0,20] when creating a new user from facebook omniauth.
I believe Devise is expecting something in the password field to create a User. Since there is no password when doing facebook oauth (not on your app side at least), you just need to create a dummy password as show above.
See this for more info:
https://github.com/plataformatec/devise/wiki/OmniAuth:-Overview