Rails 3: which strategy for authenticating to Force.com is the best for me?
There has been some recent discussions on the activesalesforce Google groups about the best options for authenticating against the Force.com database for building apps. Here are a few thoughts based on the major user stories I see, and how to approach them
There has been an active discussion recently on the ActiveSalesforce Google group regarding Rails 3 and authentication. It seems there is still some confusion about authentication in general when connecting to the Force.com database from a Rails 3 app. Early as it is here on the west coast, let me try and add a few thoughts to make it easier for developers when deciding how to authenticate.
I'm going to use user stories to logically group the thoughts. I think it is important to separate the use case from the technical implementation first, then determine which technical solution, in particular ones that relate to Ruby and Rails in this case, that are correct.
1. I'm writing a mobile app where information presented is based on the role or profile within Force.com.
The core requirement here is that you two options: provide the ability for the app to store user credentials, or use OAuth to delegate out that responsibility. I'm in favor of delegation, why re-invent the wheel especially when, in this case, the option requires storing confidential information on your phone/tablet/etc. As Ronald Reagan said, "Surround yourself with the best people you can find, delegate authority, and don’t interfere."
I would use Omniauth to delegate the OAuth dance, and spend my time building the killer app. I recently wrote how-to on using Omniauth with Rails3 and Httparty to build mobile apps which should get you started. What's more, Cloudspokes recently ran a competition to build a Force.com Omniauth strategy. The winner was Michael Bleigh, the author of Omniauth github project. I'm excited to say Omniauth now includes Force.com support in the official gem! (note: the author missed an important response variable, refresh_token, in the custom strategy. I'm in the process of making a pull request to fix it)
2. I'm writing a public website or app that presents the same information to everyone.
In this scenario, you don't need Force.com to provide information based on specific users. Your website or app can connect as a single 'integration' user. Ray Gao's asf-rest-adapter is a good fit for this, you just need to include the integration users credentials in the yaml file, just as you always have with the active-salesforce adapter. Or you could use the OAuth2 username-password flow (see below) which works very well especially if you want a lightweight REST solution.
3. I'm writing a website or app which contains both public and private (authenticated) information.
Here is where the advantages of a Cloud platform and database with easy to configure data security all the way down to the field level really shines. Here's why, and what I would do if creating the app:
My first requirement would be configure the security settings in the Force.com database to identify public vs. private data. My app or website should not need to know anything about what information is public or private, save for perhaps sections of the site which require authentication (note: this means I am encapsulating authentication details in my apps configuration vs. data views). Keep in mind to make all 'public' information also available to the private roles and profiles you set up. I'll explain why in a bit.
Next, I know my app needs to connect and authenticate. I don't want to have two different strategies for authentication. Again, OAuth is the trick. We can handle this requirement using the integration user strategy described above, but use the Username-Password flow (check out Digging Deeper into OAuth 2.0 for more info) for 'public' access. This approach will allow a visitor to view data as defined by the public roles in the database.
Lastly, whenever a user goes to an authenticated page, we can purge the 'public' token obtained from the Username-Password flow and require the user to login via our Omniauth strategy defined in #1 above. Upon successful login, the user now has access to both the private and public information. (remember we configured our database security to allow the private user profile to see all private and public data)
The nice approach to the strategy described above is that you are always using the one authentication mechanism, OAuth, but adjusting the flow based on the state of the application.
Note: At the moment, there is no clean example of #3 for folks to use as a guide. Over the next week or so I will update my Omniauth example app to provide examples of doing this. Stay tuned, or help 🙂
That's about it. Hopefully the few notes above help identify a few strategies for authenticating with Rails, and really any app. Just remember to look at the user story first, then decide on the best fit solution. When in doubt, think of what Frank Lloyd Wright said " 'Think simple' as my old master used to say – meaning reduce the whole of its parts into the simplest terms, getting back to first principles"