Seeking a single sign-on solution in Rails
Here’s a scenario for you. Lets say you’re planning to build 8 Rails applications over the next 12-18 months. These applications must all talk to one another, but that’s a separate issue from the very first problem you encounter: the login. For user simplicity, among these 8 applications, the user(s) must have only one login. For instance, if the user registers with any one of the 8 applications, they are automatically “registered” for the other 7, but cannot have access until granted (either by payment or a higher power). How would you go about this? What’s the most efficient “best practice” in terms of a single sign-on solution in Rails?
This scenario fits in nicely with what I need to start at work. The two possible routes we’ve been considering are: 1) build a custom, external users web service to manage all of the registration and 2) use OpenID. The first solution sounds appealing, only I’ve never built this kind of solution before (an API), and I’m unaware of the things I should be forewarned about. I don’t really know where to start with developing an API, but that might be another post in itself. I’ve read a little bit about ActionWebService, but haven’t delved into it heavily. I’m hoping I can build the application as a stand-alone application (the user(s) management), then extract out some methods I want for the API, and worry about that at the end. But maybe I should set things up differently in the beginning. I just don’t know, yet.
I’ve also considered just using the same database for the users information, and having a custom Users model in each application that uses establish_connection to get to the users database, but that seems to repeat too much code. Maybe there’s a way to write a plugin to hold all of this code, but then when things change, I’d have to reinstall the plugin across all 8 applications. Plus, I’ve never written a plugin, either, so I don’t know what’s involved, or if that would even work for what I need.
Ultimately, we will want the ability to login using a username/password along with the option of using an OpenID. But I believe we’re going to start with username/password logins. Anyway, do you have any thoughts on how to provide a solid, single sign-on solution for approximately 8 applications written in RoR???

Chris Wednesday, 10 Jan, 2007 Posted at 05:11AM
I haven’t messed with OpenID, but at WVU we have multiple apps talking to a central authentication system (ActiveDirectory). My solution was to create a plugin, and then use an SVN external to reference it. That way, I can easily fix bugs in the plugin’s repository, and then apply these fixes to any project that uses the plugin with a simple
svn update.Creating a plugin is quite simple:
ruby script/generate plugin CentralAuthentication.This creates all the basic files in
vendor/plugins/central_authentication.Now, in my case, the auth database already exists and I didn’t have to worry about it. In your case, your plugin would be the proxy between the database and the apps. Further, you could easily have a flag indicating if the account is an OpenID account, and pass authentication directly to that system.
The web service idea is definitely a possibility, but it will be you’ll have to manage one more app, which could be annoying. And by the way, with ActionWebService (at least in Rails 1.0) I had to have a copy of the API file in every app that uses it (which could be handled via a plugin).
Ryan Wednesday, 10 Jan, 2007 Posted at 07:22AM
So, essentially, the plugin would be responsible for using the
establish_connectioncall to the database (is that what you meant by ...the proxy between the database and…)?Right now, I’m leaning towards the web service approach, just because I’ll have to do it for other things, and maybe I’ll learn a thing or two early on. I’ll have to look into requiring a copy of the api file in every app, though—that might get old. Do you mean the file located in
app/apis/api_file.rb?Chris Wednesday, 10 Jan, 2007 Posted at 07:40AM
Yeah, I believe that’s where they are stored. What I would do is store the API file with the web service repository, and then use an svn external to reference it in the clients.
Ryan Wednesday, 10 Jan, 2007 Posted at 07:56AM
Ok, thanks for the tip. I’ll have to look into using an svn external, as I’ve never done it before.
Ryan Thursday, 18 Jan, 2007 Posted at 09:49AM
@Chris: I’m toying around with AWS and I’ve realized what you were saying about storing the API file in each application, so if I continue with this solution, I need a way to reference it in one place. How do you use an svn external? I’ve looked it up a little, but nothing seems clear-cut to me.
Wes Thursday, 26 Jul, 2007 Posted at 08:15AM
Ryan: I stumbled across this post while searching for something else, but it’s the exact problem I’m facing. Right now, we’ve got various small apps, all with their own users table. Moving these into one login would be super helpful.
What did you end up deciding? How’d it go? Pitfalls? I’m curious to hear what your experience was.
Ryan Thursday, 26 Jul, 2007 Posted at 10:56AM
Wes -
I don’t know that I would take the same approach if I were to do it over. I chose to use AWS and use the API from all apps that needed it. If you’ve read through the comments, I believe I would now recommend Chris’ solution (comment #1). I didn’t know too much about plugins at that point, and couldn’t visualize the solution as clearly. Now, I completely see what he was saying.
For our case, however, it was required to be able to manage paid accounts (users could use/buy one or all of the services, promotional codes, 30-day trials, etc), so it almost made sense to us to have this as a separate application (centralized user management) with an API into it. Unfortunately, the project ceased and we were left with a web-service interface to all of the apps, for essentially no reason. I mean, it works, but the maintainability is less than desirable. What Chris mentioned in the first comment was true: I had to include the API file in each application. I found that the changes to the API were constant, which was a bit irritating. And remember, coupling to other applications for something as crucial as a login is kind of scary. With FastCGI, if it’s dormant for a small amount of time, it takes about 10-12 seconds to start back up—so you’d also have to worry about keep-alive’s.
I would recommend taking the plugin route. You would just have a central authentication database and a plugin. The plugin would handle the authentication methods and all of the DB connections to the authentication database. Updating the authentication for each application is as easy as updating the plugin.
And if OpenID is an option for you, you should look into it. It’s really easy to get working with Rails, and solves a lot of the single-sign-on stuff through a 3rd-party service, which takes away the hassle of worrying about all of this to begin with.