Blog
How to add OpenID authentication to your ASP.NET MVC 3 site using Janrain Engage
Well, I finally took the time to implement OpenID/Social network log-in functionality to Would Be Better and although I had anticipated a much more troublesome process, it wasn’t entirely clear how I had to proceed on several of the steps either. I’d like to share my experiences with you.
Why.
After reading Rob Conery’s horror story about OpenID support for Tekpub, whay on earth did I decide to go ahead with implementing it for Would Be Better? Well, I figured that people would not quite enjoy the idea of having to create yet another account, with it’s corresponding username and password just to be able to use my puny site. At this point I have to remove all possible entry barriers as it is hard enough getting potential users to sign up, so I assumed that allowing people to sign up/in with their Facebook, Windows Live or Gmail account might help things along.
How.
I’m sure there are various ways to allow your users to sign in to your site with openID but having seen several sites using the Janrain Engage widget, including Tekpub, I thought I’d take a look. It turns out they have a free Basic plan for up to 2500 users, and since the day that Would Be Better actually has 2500 users is for now only a wet dream I went ahead and signed up.
Initial setup
The URL where Janrain Engage will send the authentication response is set up when generating the code for the widget. So, Imagine we have an ASP.NET MVC application call MyMVCApp (-1 for originality, I know), and in there we have an Account controller, and we want the Authenticate action to handle Janrain’s response. This is how our widget generation page looks like right now:
If you follow the instructions on the page and “place the code directly in the page where you’d like widget to appear you’re good to go. Almost.
You’ll have to choose some providers next. Some of them require some rather annoying set up, and it is rather unfortunate that a couple of the most popular providers are among those. Would you wanna implement social network login in your site without actually offering Facebook or Windows Live (Hotmail)? Didn’t think so.
In case you’re wondering, these are the providers we chose for Would Be Better:
Facebook requires you to create a Facebook app, and Janrain requires you to register an application with Windows Live. The latter can be a bit confusing, because you’ll have to provide the Janrain domain (something like https://mymvcapp.rpxnow.com/) instead of your own domain when registering the Windows Live app. This makes it impossible for Windows Live to “verify your app”, but it turns out it’s not necessary for the widget to work properly.
Receiving Data
Finally, what you, in all likelihood, came here for; it’s time to get this baby to talk back to us.
First, get the C# helper class provided by Janrain, called Rpx, and add it to your Visual Studio solution. Now we can create the action method Janrain will talk to: go to your AccountController and add the following action:
public ActionResult Authenticate(string token)
{
if(!string.IsNullOrEmpty(token))
{
var rpx = new Rpx("Insert Janrain API key here",
"https://mymvcapp.rpxnow.com/");
var response = rpx.AuthInfo(token);
var parser = new RpxResponseParser(response);
if (parser.Status == RpxReponseStatus.Ok)
{
var responseUser = parser.BuildUser();
return AuthAndRedirect(responseUser);
}
}
ViewBag.Message = "There was a problem signing you in."
+ "Verify your credentials and try again.";
return RedirectToAction("create");
}
OK, so what’s going on here? Janrain will post a response to our action including an authentication token. We simply get the token and use it to call the AuthInfo method on the Rpx helper class we got from Janrain, which will return a nicely formatted XmlElement with some information about the user that has just logged in.
And that RpxReponseParser? That’s just a small helper class I put together that uses LINQ to XML to help me parse the xml response and return a User object with the Username, email, openID and display name filled in. If you want, download the RpxReponseParser class, along with the RpxReponseStatus enumeration, but remember you’ll have to create the User class yourself.
Wrapping up
As you might have gathered, this code is, with minor adjustments to post it here, straight from the Would Be Better codebase. So what’s up with the AuthAndRedirect method? Well, at Would Be Better we support both traditional username/password accounts and, recently, openID/social network login account.
Since we added social network login support much later that regular username/password accounts, we actually wanted to enable anyone to be able to login with both types of account because, let’s face it, one-click login with MyOpenID is that much easier that typing your username and password. To avoid people with duplicate accounts , once you login with whichever method we try and synch user accounts based (mainly) on e-mail address. That little bit of black magic happens in the AuthAndRedirect method.
I hope this helps.
9 comment(s)
Hey AWJ,
Actually, ASP.NET MVC should take care of that as long as the token is POSTed as a form param.
You can also retrieve the token by doing: var token = Request.Form["token"];
Please note that the argument in your action MUST be called token, otherwise the framework won't be able to match what's in the Request.Form with the arguments in you action.
Hope this helps, otherwise lemme know!
Cheers,
Sergi
Thanks - I wasn't aware of that shortcut.
I have a setup which appears similar to yours. However, my problem is that after Engage has opened the window with "http://[your domain].rpx...." and at the stage in the process where it's supposed to redicrect back to the token URL (in my case a view called 'rpx', and in your case apparently a view called 'Authenticate') I get an error page (from my own app) saying
The view 'rpx' or its master was not found. The following locations were searched:
~/Views/Blog/991f9cd4defa3c4e0dc782bd2c1e5263434043e6.master
~/Views/Shared/991f9cd4defa3c4e0dc782bd2c1e5263434043e6.master
I don't understand why it can't find /blog/rpx, and why it's using the path with what appears to be a double-length GUID.
Also, when this error page appears, if I simply refresh the page (/blog/rpx) then the view appears. So the view and its action ARE there.
Any ideas why Engage seems unable to redirect to my /blog/rpx page?
@AWJ,
The only thing I can think of off the top of my head is to verify that you've set up the url correctly on the Engage site (see step "Initial Setup" on this post).
It looks as though Engage is trying to use the "token" parameter as the Action name.
gss
dfgdsfs
Thanks you for the useful blog
This helped me a bunch... Thanks!
Curious to see the Authenticate step.. do you call something to then engage the asp.net membership cookie as well?
Thanks for the great post; it's a real time/sanity saver.
I've been looking for a straightforward implementation of OpenID based authentication the past few days. Between the Janrain widget and your post on integration it's saved me a ton of time.
Thanks!

Sergi,
I'm struggling to achieve something similar on my MVC app. Could you possibly explain how the token is passed to your controller method in the above example as I understood that it was passed as a POST form paramater, so how did you manage to get it passed to your controller method as an argument?