ASP.NET: Using OAuthWebSecurity without SimpleMembership

I’ve been researching the new support in ASP.NET for OAuth and OpenID authentication. It provides a nice and easy to use wrapper on DotNetOpenAuth. The main APIs are on the OAuthWebSecurity class and they provide methods to authenticate against your OAuth and OpenID providers as well as associate those OAuth and OpenID accounts to an account with your local membership provider (and strictly speaking your simple membership provider). Personally, I dislike the coupling between the authentication piece and the persistence piece. Fortunately this API can still be used without using providers.

The main APIs to be aware of are:

  • OAuthWebSecurity.RegisterXxxClient
  • OAuthWebSecurity.RegisteredClientData
  • OAuthWebSecurity.RequestAuthentication
  • OAuthWebSecurity.VerifyAuthentication

RegisterXxxClient (where Xxx is: Microsoft, Twitter, Facebook, Google, Yahoo or LinkedIn)

The various Register APIs allow you to initialize which OAuth/OpenID identity providers you want to use (many of these require passing your application identifier and secret).

RegisteredClientData

This API provides the list of the registered identity providers. This is necessary for the ProviderName property when requesting authentication.

RequestAuthentication

This is the API to invoke to trigger a login with one of the identity providers. The parameters are the identity provider name (so one of the ProviderName values from the RegisteredClientData collection) and the return URL where you will receive the authentication token from the identity provider. Internally it does a Response.Redirect to take the user to the identity provider consent screen.

VerifyAuthentication

This API validates the authentication token from the identity provider and returns the results. You can then use these results to log the user into your own application (typically with Forms Authentication). There is also additional data returned from the identity provider such as email, gender, etc. Different identity providers return different information.

So to trigger the authentication, this is all you need to do:

[AllowAnonymous]
public void LoginWithProvider(string provider)
{
    OAuthWebSecurity.RequestAuthentication(provider, Url.Action("AuthenticationCallback"));
}

[AllowAnonymous]
public ActionResult AuthenticationCallback()
{
    var result = OAuthWebSecurity.VerifyAuthentication();
    if (result.IsSuccessful)
    {
        // name of the provider we just used
        var provider = result.Provider;
        // provider's unique ID for the user
        var uniqueUserID = result.ProviderUserId;
        // since we might use multiple identity providers, then 
        // our app uniquely identifies the user by combination of 
        // provider name and provider user id
        var uniqueID = provider + "/" + uniqueUserID;

        // we then log the user into our application
        // we could have done a database lookup for a 
        // more user-friendly username for our app
        FormsAuthentication.SetAuthCookie(uniqueID, false);

        // dictionary of values from identity provider
        var userDataFromProvider = result.ExtraData;
        var email = userDataFromProvider["email"];
        var gender = userDataFromProvider["gender"];

        return View("LoggedIn", result);
    }
    return View("Error", result.Error);
}

It’s really up to you how to identify the username when you’re logging them in with FormsAuthentication, but it’s important that to uniquely identify your users your must use both the provider name and the provider user id. In the above snippet we’re just logging the user in with that, but you could built your own back-end database to allow users to manage their own username for your application. This mapping is in essence what the new SimpleMembership system is doing, and if you don’t need or want to control the database schema then it’s a fine solution.

Also notice the extra data from the authentication result. This contains additional user information the identity provider has returned to the application. From what I can tell, here is the breakdown (beyond ProviderUserId) of what data each provider returns (these are the actual keys used in the ExtraData dictionary):

Google: email, country, firstName, lastName
Microsoft: name, link, gender, firstname, lastname
Facebook: username (which is really an email address), name, link (URL to their facebook page), gender, birthday
Twitter: name, location, description, url (URL to their Twitter page)
Yahoo: 
email, fullName
LinkedIn: name, headline, summary, industry

Microsoft did a nice job making it easy to use DotNetOpenAuth.

Advertisements

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s