So having had a bit of a rant about social authentication - and how few good examples I was able to find of how to use Devise’s Omniauthable module with multiple providers - I wanted to post here how I handled it. There are many pieces of this code copied directly from other sources. These sources are all referenced in my earlier post here.
Firstly, the heart of it, as per the Devise wiki is users/omniauth_callbacks_controller.rb. The other key files in my case are the user model (user.rb) and the devise config file (config/initializers/devise.rb). The code is below. Some points worth noting:
- I had to modify devise to allow login either via username or email in order to support twitter (and not force users to have to provide an email after authenticating). This is mostly covered in the Devise wiki here.
- In order to allow those authenticating via oauth to edit their user settings (when they have no password) I had to follow this.
- Since accounts can be edited without a password, I removed the ability to edit password via the user registration form. The only way to alter password was then via the ‘forgotten password’ mechanic via email. (So for example if after first authenticating via twitter, and the user wants to configure a password to log in directly, then they will have to first provide an email before updating their password. This is a touch clumsy but still more intuitive than forcing twitter users to enter their email just to complete the initial authentication.)
- Adding new providers is now pretty straightforward. The provider specific code is mostly confined to the provider_user_hash and provider_auth_hash blocks at the bottom of omniauth_callbacks_controller.rb
Probably still much could be improved here - but it is the closest I have gotten so far to a ‘seamless social authentication’ using Devise and Rails.