Speaking to @JacoPretorius earlier in the week the samples that come with the DotNetOpenAuth (http://www.dotnetopenauth.net/) libraries weren’t clear. To be honest I couldn’t even get the samples to run, firstly because the project types weren’t up to date & also because the references to the MVC libraries were wrong. I also wanted to get it running in VS2010. Rather than labour with getting it running in VS2008 I had a quick scan of the source code & set to work figuring it out. The article that follows describes what needed to be done to get the MVC sample application integrating with Twitters OAuth mechanism.
I’m not going to detail the OAuth process here, there are plenty of articles around that do that already. I will summarise it from a dev perspective though – you redirect the user to a 3rd part auth provider (e.g. twitter, google, and many others) using a standard http redirect. The details at the auth provider end will vary, but may include the user authenticating themselves & authorizing the calling application (i.e. your app) to access there identity. The auth provider then redirects back to the calling application passing an encrypted string, which contains the users identity. The details here will vary depending on the auth provider.
I do have a couple of gripes with the implementation of the OAuth protocol based on what I’ve seen with twitter & google (this may not apply to all OAuth providers); it seems you need to register with each provider you want to support (I couldn’t even register with google because it’s integrated into the google webmaster tools & needs to verify against a real site), you then need to store credentials for each of those providers in your application, finally it doesn’t seem like there’s a standard set of attributes in the identity that gets returned to allow you to extract info such as user ID. You basically get a set of name value pairs in an "Additional parameters" collection, on twitter the username is in a property called screen_name.
The code below is just to illustrate be refactored as I add more providers but for now
Onto the real work…
I’ve started with the basic asp.net MVC starter site:
First you need to set yourself up as an oath client with twitter at http://twitter.com/oauth_clients/, the details here don’t seem to matter – I used a website URL that isn’t live yet & it was fine – when you’re debugging locally the redirect back from twitter after authenticating
Then reference the correct assemblies – you’ll need to find them in the samples, and put them wherever you’d normally put dependency libs:
DotNetOpenAuth
DotNetOpenAuth.ApplicationBlock
I then setup the references I need:
using DotNetOpenAuth.ApplicationBlock;
using DotNetOpenAuth.OAuth;
using DotNetOpenAuth.OpenId;
And a static field & property to store the twitter credentials:
private static InMemoryTokenManager _tokenManager = new InMemoryTokenManager("Twitter Consumer key", "Twitter Consumer secret"); private InMemoryTokenManager TokenManager { get { return _tokenManager; } }
Then modify the login view views/account/logon.aspxto include a "login via twitter" option as a simple link (I used an action called TwitterOAuth on the Account controller to wrap up my logic for preparing the request to twitter):
<a href="<%= Url.Action("TwitterOAuth") %>"><img src="../../Content/images/oauth/twitter/twitter_button.gif" alt="twitter oauth button" /></a>
It may look something like this:
The server side component consists of two requests, one when the user clicks the button & one when the auth provider redirects the user back. I have a TwitterOAuth action & a OAuth action.
In the TwitterOAuth action I use the dotnetauth library to construct a wrapper around the twitter OAuth API, prepare the URL that I want the user to be redirected back to & send the request, which redirects the user to twitter to authenticate.
public ActionResult TwitterOAuth() { var twitter = new WebConsumer(TwitterConsumer.ServiceDescription, this.TokenManager); //Create the URL that we want Twitter to redirect the user to var oAuthUrl = new Uri(Request.Url.Scheme + "://" + Request.Url.Authority + "/Account/OAuth"); // If we don't yet have access, immediately request it. twitter.Channel.Send(twitter.PrepareRequestUserAuthorization(oAuthUrl, null, null)); //This shouldn't happen!! return null; }
In the OAuth action I’m going to process the response from Twitter and if successfully authenticated store the identity in the ASP.NET forms authentication cookie & redirect to the home page:
public ActionResult OAuth() { var twitter = new WebConsumer(TwitterConsumer.ServiceDescription, this.TokenManager); // Process the response var accessTokenResponse = twitter.ProcessUserAuthorization(); // Is Twitter calling back with authorization? if (accessTokenResponse != null) { //Extract the access token & username for use throughout the site string accessToken = accessTokenResponse.AccessToken; string username = accessTokenResponse.ExtraData["screen_name"]; CreateAuthCookie(username, accessToken); } else { //If the request doesn't come with an auth token redirect to the login page return RedirectToAction("Login"); } //Authentication successful, redirect to the home page return RedirectToAction("Index", "Home"); } private void CreateAuthCookie(string username, string token) { //Get ASP.NET to create a forms authentication cookie (based on settings in web.config)~ HttpCookie cookie = FormsAuthentication.GetAuthCookie(username, false); //Decrypt the cookie FormsAuthenticationTicket ticket = FormsAuthentication.Decrypt(cookie.Value); //Create a new ticket using the details from the generated cookie, but store the username & //token passed in from the authentication method FormsAuthenticationTicket newticket = new FormsAuthenticationTicket( ticket.Version, ticket.Name, ticket.IssueDate, ticket.Expiration, ticket.IsPersistent, token); // Encrypt the ticket & store in the cookie cookie.Value = FormsAuthentication.Encrypt(newticket); // Update the outgoing cookies collection. Response.Cookies.Set(cookie); }
That’s it! You should now see the logged in user in the top right corner & the logout method will work as expected:
Curious what problem you were seeing with the references that you say needed to be fixed up. They worked for me straight out of the download .zip file.
Anyway, thanks for sharing your experience.
By: Andrew Arnott on March 21, 2010
at 12:40 am
I’m going to package the source code into a demo app next week so I’ll take another look then & let you know.
By: craigtech on March 26, 2010
at 8:31 am
Could you kindly release the source code project for this? Thanks!
By: Steven on March 22, 2010
at 8:26 pm
Will try to release the source code next week.
By: craigtech on March 26, 2010
at 8:31 am
Thanks dude – awesome post. Do you know if it’s possible to do OAuth the way StackOverflow does – it allows you to choose a provider OR just type in your URL…?
By: Jaco Pretorius on March 24, 2010
at 8:32 am
Ok it seems I’m confusing OAuth with OpenID…
By: Jaco Pretorius on March 24, 2010
at 8:43 am
That was really helpful. You solved my problem and gave me a fresh way to deal with Oath.
Thanks
Michelle
By: Michelle Hewitt on April 25, 2010
at 11:25 pm
Geat articel, any news on the source code?
By: Alec Dobbie on April 26, 2010
at 1:11 pm
It sounds like the provider you’re integrating isn’t using OAuth, which provider is it, I’ll take a look.
By: craigtech on September 7, 2010
at 1:34 pm
Nice article.
Can you explain the benefit of your CreateAuthCookie method. Why use that as opposed to FormsAuthentication.SetAuthCookie
Thanks!
By: Andrew on March 16, 2011
at 6:08 pm
Hi Andrew,
It stores the users twitter username and auth token, encrypted, in the cookie. You could store it in session but then you’d need to maintain the session for a long time.
Hope that makes sense.
Craig
By: craigtech on March 16, 2011
at 6:30 pm
christ, the dotnetauth guys don’t make things easy do they?!
I can’t find a reference to ChannelElements.IOpenIdOAuthTokenManager now.
not knocking this tutorial by the way, it has been very helpful in understanding a very complicated and unexplained dotnetopenauth library.
By: mark rogers on November 16, 2012
at 4:09 pm
Mark, the interface you can’t find is defined in this NuGet package: http://nuget.org/packages/dotnetopenauth.openidoauth
By: Andrew Arnott (@aarnott) on November 16, 2012
at 4:38 pm
I entered the command line into my package manager console and it still does not recognize the library
By: mark rogers on November 16, 2012
at 5:31 pm
I had to add the ApplicationBlock as an existing project, and then I had to add the DotNetOpenAuth dll to my main project, because the Nuget Command line hadn’t added that for me
By: mark rogers on November 16, 2012
at 5:35 pm