Omnoauth login using Linkedin not supply email in info hash - ruby-on-rails-3

I am using omniauth with LinkedIn as a provider. LinkedIn doesn't supply
an email in info hash, so i cannot provide an email when create the user based
on the information I get back.
Two related questions:
1) How can I adjust devise so that there isn't a requirement
for :email as a validation? It doesn't appear to be set under the
User model.
2) I do want to get the email information, however, so want to have
email information requested before creating the User. How can I
redirect to a page/wizard asking for email information and then come
back to finish the user registration?

I just solved this without needing to use the separate 'linkedin' gem, it was pretty difficult as there was a distinct lack of documentation on the subject!
Firstly you need to make the email-address available by adding the fields option to your LinkedIn Omniauth configuration, you will also need to override the request_token_path in order to add the r_emailaddress scope required to retrieve a users email address.
Mine ended up looking something like this (NB. Ruby 1.9.3):
provider :linkedin, external_services['linkedin']['api_key'], external_services['linkedin']['api_secret'], client_options: {request_token_path: '/uas/oauth/requestToken?scope=r_emailaddress'}, fields: ['id', 'first-name', 'last-name', 'headline', 'industry', 'picture-url', 'public-profile-url', 'email-address']
NOTE: Dont forget to change external_services['linkedin']['api_key'] and external_services['linkedin']['api_secret'] to your own.
Your user will then be asked to authorise use of their email address as well as their basic provide and you will have access to it once they are returned via:
auth['extra']['raw_info']['emailAddress']
I should probably commit this change back to omniauth-linkedin so you can simply set scope: r_emailaddress in the provider options, avoid the duplication of the field names and get the email back in the info section of the auth object.
If I get time after this section of my project is finished I will.

Take a look at the railscasts about omniauth: http://railscasts.com/episodes?utf8=%E2%9C%93&search=omniauth
The idea is the following:
Create a new user from the omniauth info
try to save the user
since the email is not present it won't validate
store the omniauth data in the session and redirect_to new_user_registration_url
create your own registration controller that inheritates from the devise one
override the build_resource(*args) method, and if the omniauth data is present, use it to create the resource (User in your case)
That way, after trying to login with linkedin, the user will be redirected to a form where he will be able to enter his email.
It's all explained in the railscast ;)

Related

Different devise confirmation process for same model

I am using Rails 3.2.15 and Devise 2.2.8. I want to have different email confirmation behaviour for same model depending on certain conditions.
Case 1: User signs up on his own using an email and password, gets Mail Template 1 (the mail only asks for email confirmation, he has already set the password)
Case 2: A new user is added in model explicitly by another registered user. The new user gets Mail Template 2, which asks him to reset the password (reset should by default confirm his account as well)
Is this possible to achieve?
I was going through Devise page where we can override confirmation process to let user set the password and auto-confirm the account during this process. But I think this will happen for all users added in model. I want to customize this.
You probably found your answer; but for future ref, if the answer is needed, I just wanted to say that YES, this is possible...
As usual with Rails, you can override anything so this is also true for the confirmation process in Devise.
I'm working on a project where we have different ways of accepting/confirming new users.
If you/somebody needs details, feel free to ask...
Cheers

invite users via devise without creating a new user until the invitation is accepted

I want to invite users to different events that are in my database and my user model is managed via devise.
With devise_invitable apparently every time I want to invite a user a new record is created or I get an error if the user identified by email already exists. Both is a problem in my use case since users should get access to events based on those invitations (which is handled already) and users potentially sign up to different events with different email addresses, still all should be one account.
So is there a way to convince devise_invitable to not create a new user account at the time of the invitation but only when the invitation is accepted and there isn't a logged in user?
Not really, Devise (and Devise_Invitable) was only intended as a registration for a User to a single service hence making the email address unique.
Have you thought of using Devise_Invitable purely as a registration service and just extending your User object to include a has_many EventRegistration attribute to store your event and email address combinations as you mentioned?

Devise/OmniAuth - LinkedIn: Email is blank in callback

I'm using Devise 2.1.2 with multiple OmniAuth providers. My devise.rb file contains this line:
config.omniauth :linkedin, API_KEY, SECRET_KEY, :scope => 'r_emailaddress', :fields => ["email-address"]
It is currently stripped down to just email-address since that is the only thing acting strange. Taking a look inside request.env['omniauth.auth'].info, the email key is blank.
How come? I don't want to bypass validation, I wan't to use the email address from the users LinkedIn account.
Thanks to the thread link in Remus Rusanu's answer, I noticed this post by a LinkedIn employee:
Hey guys, we're working on a migration plan for existing applications. The new member permissions only apply to newly registered applications.
Thanks!
Kamyar
Due to no patience, creating a new LinkedIn application allowed me to retrieve the user email address. How nice that they finally changed their mind about this.
Given that LinkedIn as a matter of policy does not share the email over oauth, I'm not at all surprised.

Set a password after creating an account with Omniauth (Rails + Devise)

How can I let users set passwords once they create an account through Omniauth? Omniauth creates a stub password during registration, but the user does not know what that password is, therefore cannot change it from the edit user page.
I tried to override the edit form with the instructions here: How To: Allow users to edit their account without providing a password. I was able to change the encrypted password in the db, but cannot log in with the new password, and weirdly enough, I do not see any errors in the console during log in failure.
Any ideas?
I am using Rails 3.0.7 and Devise 1.4.8. My sign-in/sign-up code is based on the standard Omniauth+Devise tutorial.
Omniauth only provides you with information on a remote user, with the guaranty that this user is connected to the provider. You then have three options :
create a user with that information, and set fields that are not specified with default method (which is what you did for password)
use that information to prefill devise sign up form (self.new_with_session as described in your tutorial) and let users create their account themselves, filling in the missing fields (such as password)
store the omniauth information in a session (or cookie), redirect your user to a form with the missing fields, and use both form information and session information to create your new user.

Rails 3 App: for oAuth-only sign-in using Facebook and Twitter, should I use Devise/OmniAuth, or just OmniAuth?

I'm creating a new Rails 3 app and I want to allow users to sign-in using their Facebook or Twitter credentials.
I don't know whether I should implement this using Devise and OmniAuth, or just OmniAuth. I just watched Ryan Bate's screencast on Simple OmniAuth and it seems like I could just use OmniAuth, but I'm not sure it's enough.
I have the following requirements:
Allow sign-in via Facebook and/or Twitter. I will not be implementing local user accounts/passwords.
Signing in via FB/Twitter for the first time should create a new user in the db so I can store the associated FB/Twitter oAuth tokens.
Users should be able to associate both a FB and a Twitter acct to their profile/user so they can post to both FB and Twitter.
Users should be able to delete their account.
I posted this on the Devise Google Mailing List and got this response from José Valim (Devise maintainer and Rails core team member):
"You can use just OmniAuth. If you use Devise, the only benefit is that it will add Omniauth url helpers, but that is so minimal that honestly is not worth the overhead."
-- José Valim
Devise is a fancy way to automatically handle all the things that go with user accounts. If you don't need all the bells and whistles, you should definitely just go the Simple OmniAuth way like in the screencast.
The only hitch I see with trying to link up a Facebook and Twitter account is that you'll have to require them to be signed into one in order to link the other -- and if they do happen to sign in on separate occasions, you could possibly have two Users in your database. This wouldn't be a problem if you were doing Google and Facebook because they both send back an email address, but Twitter only sends back a username, no email address.
You'll have to add a field to the User model for a username (Twitter) and email address (Facebook) so you can attempt to link the accounts if a visitor did it separately and wants to link them later. Just be careful of that when you set it up.
If you can't use just OmniAuth, maybe because, like in my case, you want to use ActiveAdmin which depends on Devise and methods like current_user would conflict, you can just override the login page with your own:
match '/users/sign_in', :to => "sessions#new"
devise_for :users, :controllers => { :omniauth_callbacks => "users/omniauth_callbacks" }
I have a "Sign in with Facebook" link in my nav, but this page is necessary for redirecting users when they're trying to access a protected page while not logged in.
Edit: Actually, there is a section on the wiki page: "Using OmniAuth without other authentications"