Real World OAuth using ASP.NET MVC

Posted by: Sumit Maitra , on 6/13/2013, in Category ASP.NET MVC
Views: 245167
Abstract: This article demonstrated how to hack into the new OAuth integration using DotNetOpenAuth in an ASP.NET MVC application and retrieve all possible user information from the Provider.

If you haven’t heard of OAuth or OpenID you have most certainly used it in day to day life. Have you provided your google username/password and logged in to StackOverflow or used your WordPress.com account to post comments on someone’s blog or used third party Twitter clients whom you have given permission to use your Twitter account or used Facebook to post comments on some tech blog site? If answer to any of the above is a Yes, you have seen OAuth or OpenID in action.

This article is published from the DNC .NET Magazine – A Free High Quality Digital Magazine for .NET professionals published once every two months. Subscribe to this eMagazine for Free


What is OpenID and OAuth

At a 100K feet both are Authentication protocols that work towards a dream on the web, that is - Single Sign On. Basic premise being, instead of having to remember a different username and password for every Application we visit on the internet, we have a dedicated Authentication provider with whom we register our user name and password. Applications (aka Relying Party) redirect us to this provider for authentication and after a successful authentication, the provider passes back a token to the replying party who initiated the request. The target Application then uses the token to verify the identity of the person and provide further access to Application Features.

OAuth was initiated by Twitter when they were working on building their OpenID implementation for Twitter API. Their need was more towards controlling what features to make available based on Authentication Types offered at the Provider and those sought by the relying party.

For example when a Relying party signs up for Twitter Authentication access, they can request for a Read-Only connection (this gives them read permissions to a user’s stream), a Read/Write connection (this gives them read and write permissions on a user’s stream) and a Read/Write with Direct Messages connection (giving them maximum possible access to user’s data). Thus, when a user authenticates with Twitter over OAuth, they are told exactly what kind of access they are providing.

On the other hand, OpenID simply ensures that you are who you claim to be by verifying your username and password. It has no way of controlling feature access.

In even simpler terms, OpenID is about Authentication, OAuth is about Authentication and Authorization (for features at the Provider).

oauth-provider-auth

The diagram above demonstrates the Authentication process for an OAuth provider. The overall workflow is as follows:

1. Application (Relying Party) registers with OAuth provider and obtains an Application specific key (secret). This is a one-time process done offline (not shown in above image).

2. Next the Application (Relying Party) has to pass the Application key to the provider every time it intends to authenticate someone.

3. User of the Relying Party needs to be registered with the Provider (again a one-time offline process)

4. Every authentication request directs the user to the Auth Provider’s site. The user enters the Username and Password that they obtained by creating an account with the provider. The Provider verifies the account credentials, then it matches the Application Key and provides a token back to the Relying Party with which only the Authorized actions can be performed.

I have a bunch of references up on the Github page for this article feel free to go through them if you would like to understand these protocols in greater depth.

Twitter OAuth and ASP.NET

Today we will learn how to use ASP.NET’s integration of the DotNetOpenAuth library that allows you to integrate using Twitter/Facebook/Google Id and other similar providers. Most examples on the net kind of stop after the Authentication piece and don’t elaborate on how you can use it further. Today we’ll dig a little deeper and see what it takes to go beyond the default implementation provided by ASP.NET and extract further information from our OAuth provider i.e. Twitter.

Getting Started – Registering an Application with Twitter

As we saw above there are four steps, let’s get started at Step 1, registering our application with Twitter.

1. Navigate to http://dev.twitter.com/ and click on the Sign In (top right)

twitter-signin

2. Log in using your Twitter credentials. Hover over your Account Info and Click on ‘My Applications’

my-applications

This will take you to the Applications page where you can register a new Twitter Application. This is going to be the Relying Party.

3. Next click on ‘Create a new application’ and navigate to the new application page. It asks for the following details

create-application

  • Provide proper Name and Description these will come up every time a new user Authenticates at your site.
  • Specify a callback URL that would point to a site address. You can point it to http://127.0.0.1/
  • Notice the Website is setup as localhost address. This is for testing purposes. Once you have the application going set it back to the actual website.
  • Scroll down, read the Developer Rules of Road carefully and click on Yes, I agree. Fill in the captcha and click on ‘Create your Twitter Application’.

twitter-captcha

4. Twitter will navigate to a page similar to the following

oauth-demo-setup

Next click on the ‘Create my access token’ to generate the access token that our app will be using along with the Consumer Key and Consumer secret. Remember all three values shouldn’t be shared.

Also notice the Access Level is set to Read-only by default. For our application we need Read-only access, but if you would like to post tweets on the User’s behalf you can modify the permissions from the ‘Settings’ tab. Remember to regenerate the Access Token if you change the Access Level.

With that we are ready with Step 1. Let’s build the barebones of our Application now.

Using Registration information to Authenticate with Twitter

1. Create a new ASP.NET MVC Web Application and select the Internet Template.

2. Open the AuthConfig.cs from the App_Start folder and uncomment the code to register the Twitter Client

public static void RegisterAuth()
{
OAuthWebSecurity.RegisterTwitterClient(
  consumerKey: "",
  consumerSecret: "");
}

3. Put the keys in web.config and update the above code to get the values from ConfigurationSettings.

4. Update the project’s properties to run the application on the same port as specified in the URL above

app-port

5. That’s pretty much it. Run the Application and click on the Log On Link to be presented with the new Login page

app-port

As you can see we have a button to log in to Twitter. Let see what happens when we click on it.

6. On clicking twitter the application gets routed to a Twitter page

twitter-app-page

Here you will notice the following

- On the right hand side is information about your app that you provided while creating it, including the URL.

- Above the Username or email address text box is a list of things that the requesting application can do, in our case it can ‘Read Tweets from your timeline’ and ‘See who you follow’.

Note: This is why when using OAuth you have to be careful to request for only as much information as you need. If your app seems terribly nosy, the end user may choose not to allow give you permissions.

- On successful authentication you will see a brief flash of ‘redirection in progress’ message and the user will be sent back to our application again.

7. For the first time log in, we will be requested to register via the following page

register-account

8. Once you Register, you are logged in as an Authenticated user for the application

authenticated-user

9. With this we have completed Step 2, 3 and 4 of the OAuth process and this is where most demo applications draw a line.

Hacking into the OAuth Client

Since we have a working Twitter Authentication going, let us see what it takes to use the Twitter Avatar in our application. Once authenticated we expect the entire User profile to be returned to us. This profile in the Authentication result as ExtraData. However if we break in the AccountController soon after the log in, we will see ExtraData only has a handful of values that does not include the Avatar URL.

account-controller-debug

What now? After some head-scratching I concluded that there was no other option but to create a custom OAuth client for ourselves to get the required data. Essentially the default TwitterClient class that the ASP.NET team is provided is barebones to say the least.

Overriding the default TwitterClient to build one of our own

To start off with I’ve referred to the TwitterClient class from DotNetOpenAuth’s Github repository (yay for OSS), and copied the entire implementation over into a new class called TwitterClientEx.

After copying the contents over, we will need to copy over some helper methods for formatting and escaping characters, these are mysteriously implemented as internal methods.

The code in context refers to the internal static extension class DictionaryExtensions that has some helper methods. We also bring in three helper methods LoadXDocumentFromStream, CreateUntrustedXmlReaderSettings and EscapeUriDataStringRfc3986. All these methods are implemented in the TwitterClient or OAuthClient classes but are unfortunately not reusable.

With the above in place we can register it in AuthConfig.cs using the following code.

OAuthWebSecurity.RegisterClient(new TwitterClientEx(
    consumerKey: ConfigurationManager.AppSettings["consumerKey"],
    consumerSecret: ConfigurationManager.AppSettings["consumerSecret"]), "Twitter", null);

//OAuthWebSecurity.RegisterTwitterClient(
//    consumerKey: ConfigurationManager.AppSettings["consumerKey"],
//    consumerSecret: ConfigurationManager.AppSettings["consumerSecret"]);

As we can see above, we have commented out the RegisterTwitterClient static method and instead used the generic RegisterClient method and passed in our own TwitterClientEx instance. The second parameter is simply the Label by which the Client is referred to.

However so far we have merely copied the TwitterClient so we still don’t have our Avatar URL. To load the Avatar and other User Data let’s revisit the VerifyAuthenticationCore method in TwitterClientEx.

The default code has the only the following parameters extracted from the XML Document returned by Twitter.

extraData.AddDataIfNotEmpty(document, "name");
extraData.AddDataIfNotEmpty(document, "location");
extraData.AddDataIfNotEmpty(document, "description");
extraData.AddDataIfNotEmpty(document, "url");

However, instead of the above hardcoding if we have the following Loop then we can extract the complete set of values in the ExtraData dictionary.

XDocument document = LoadXDocumentFromStream(responseStream);
foreach (var node in document.Descendants("user").Nodes<XElement>())
{
if (node.NodeType == XmlNodeType.Element)
{
  extraData.AddDataIfNotEmpty(document, 
((XElement)(node)).Name.LocalName);
}
}

Now that we have retrieved the data required let’s see how we can save it for ourselves.

Saving ‘ExtraData’

By default the ViewModel objects and Data Model objects are bunched together in Model\UserAccounts.cs file that has multiple class files. Even though I dislike multiple classes per file, I’ll ignore it for the moment and we’ll simply extract the UserProfile class to a new Model\Account folder.

In this folder we will add our ExtraData class. The POCO looks as follows

public class ExtraData
{
public int Id { get; set; }
public string AccessToken { get; set; }
public string Name { get; set; }
public string Location { get; set; }
public string Description { get; set; }
public string Url { get; set; }
public UserProfile ParentUserProfile { get; set; }
public int UserProfileUserId { get; set; }
}

For brevity we will refrain from saving all the 35 possible values that can be returned in ExtraData resulting from the Authentication.

The POCO has a parent-child relationship established with the UserProfile object.

In the AccountController, the ExternalLoginCallback method is called after user returns from Twitter’s Authentication page. Here the result variable retrieves all the information returned after a successful Authentication. We populate our ExtraData POCO from the result here.

As a next step the boilerplate checks if the user exists locally and for first time access the code redirects user to a confirmation page and requests for UserId to be used in this application. This is where we can update the ExtraData poco into the database. However we need to pass all the data via the RegisterExternalLoginModel to the ExternalLoginConfirmation page. To do this we update the RegisterExternalLoginModel to carry ExtraData with it.

public class RegisterExternalLoginModel
{
[Required]
[Display(Name = "User name")]
public string UserName { get; set; }
public string ExternalLoginData { get; set; }
public ExtraData AuthenticationProviderData { get; set; }
}

In the View we add a set of Labels and Hidden Variables and an Image to represent the ExtraData on the View. There we have it, Authentication with Avataar.

auth-with-avatar

Once we click Register, the ExtraData is saved in the Application’s database and we can retrieve and use it anytime we want.

Example Usage

Now that we have seen how to Authenticate against Twitter or other OAuth providers we can use this technique for creating a Disqus like commenting system or a StackOverflow style Forum or any ‘Socially connected’ site we want.

The default implementation that comes out of the box with ASP.NET is a little light for direct practical usage but as we saw it’s not really difficult to extend it to our benefit.

Conclusion

We saw how we can build our ASP.NET application to use Twitter for Authentication. The usage scenario discussed was only the tip of the iceberg. DotNetOpenAuth is a powerful library and hidden under the lightweight wrappers created by the ASP.NET team is a real powerhouse framework that can take care of a lot of your Social Media integration requirements.

Download the entire source code of this article (Github)

This article has been editorially reviewed by Suprotim Agarwal.

Absolutely Awesome Book on C# and .NET

C# and .NET have been around for a very long time, but their constant growth means there’s always more to learn.

We at DotNetCurry are very excited to announce The Absolutely Awesome Book on C# and .NET. This is a 500 pages concise technical eBook available in PDF, ePub (iPad), and Mobi (Kindle).

Organized around concepts, this Book aims to provide a concise, yet solid foundation in C# and .NET, covering C# 6.0, C# 7.0 and .NET Core, with chapters on the latest .NET Core 3.0, .NET Standard and C# 8.0 (final release) too. Use these concepts to deepen your existing knowledge of C# and .NET, to have a solid grasp of the latest in C# and .NET OR to crack your next .NET Interview.

Click here to Explore the Table of Contents or Download Sample Chapters!

What Others Are Reading!
Was this article worth reading? Share it with fellow developers too. Thanks!
Share on LinkedIn
Share on Google+

Author
Sumit is a .NET consultant and has been working on Microsoft Technologies since his college days. He edits, he codes and he manages content when at work. C# is his first love, but he is often seen flirting with Java and Objective C. You can follow him on twitter at @sumitkm or email him at sumitkm [at] gmail


Page copy protected against web site content infringement 	by Copyscape




Feedback - Leave us some adulation, criticism and everything in between!
Comment posted by Brock Allen on Thursday, June 20, 2013 8:01 AM
You've got it wrong -- OAuth isn't about authentication.

http://leastprivilege.com/2013/04/16/authentication-vs-authorization/
Comment posted by Rick Anderson on Thursday, June 20, 2013 2:37 PM
Brock - see http://openid.net/connect/   Excellent article, I'll be linking my tutorials to this.
Comment posted by Sumit on Thursday, June 20, 2013 7:42 PM
Hi Brock,

As I said, it's a 100K feet view. Quoting from http://ouauth.net/about/

"OAuth is not an OpenID extension and at the specification level, shares only few things with OpenID – some common authors and the fact both are open specification in the realm of authentication and access control."

-Sumit.
Comment posted by liming on Friday, June 21, 2013 10:56 PM
If you use OAuth for authentication, it's just a matter of time before you get screwed.  Many people already got burned with OAuth1.0, but no one learned from it. Truly sad.
Comment posted by Stock Tips on Saturday, June 29, 2013 4:15 AM
I never in a million years would’ve considered to look at things this way. This is going to make my afternoon a bunch easier.
Comment posted by swetha k on Wednesday, September 11, 2013 11:54 AM
Excellent Post. Also visit http://www.msnetframework.com/#aspnet.php
Comment posted by Jayakumar on Tuesday, February 18, 2014 7:16 AM
hi
sumit

your code error comes DotNetOpenAuth and OAuthClient not a references here.
Comment posted by Sumit on Saturday, February 22, 2014 1:32 AM
The beauty of Web is that it's ever evolving. So Twitter API has evolved as well. The URL in TwitterClientEx.cs is not longer available and returns a 410 (Gone). This is because Twitter API 1.0 is deprecated. I am working on an updated codebase and will report back here once done.

Cheers,
Sumit.

P.S. Apologies for DotNetOpenAuth errors. Looks like I forgot to enable Nuget Package Restore. Right click on the solution in Solution Explore and enable Nuget Package Restore. The open the Package Manager Console and click on Update Packages button to get the DNOA dependencies.
Comment posted by kiran on Thursday, March 6, 2014 5:21 AM
xzvxzv
Comment posted by Joseph Emeka on Monday, August 11, 2014 1:27 AM
I was following your examples and I got stuck trying to log in with Twitter. I have pasted my customer key and customer secret in the ConfigureAuth()function for Twitter, and I have also match the URL with my Twitter app, but I am still getting a 401 (Unauthorized)error code. I tried logging in with google, and it worked fine. I am totally out of idea what the problem is.  
Comment posted by How to implement it using Asp.net Mvc3 on Wednesday, January 28, 2015 12:09 AM
Please Give Me Reply
Comment posted by aamir on Monday, May 11, 2015 1:07 AM
HOw to get email address from result... Please any idea or option