Plugging custom OAuth/OpenID providers

Plugging custom OAuth/OpenID providers

  • Comments 11

In the previous post, I wrote about how you can use the existing providers for Google, Facebook etc. and retrieve extra metadata about the authenticated users. Let’s assume you wanted to change the way the providers request for information. Some examples of this could be

  • You want to request more data about the user
  • You want to apply different scope levels when requesting the data

This post covers how you can write your own provider and plug it into your ASP.NET web application

Write your own provider

Each Provider implements from OpenIdClient. Following example shows a custom implementation of Google Provider which requests information about the user such as firstname/lastname etc

Please Note:  This addresses a bug with the existing google provider which does not return the extra data about the user such as Country/FirstName/LastName. The version of google provider is DotNetOpenAuth.AspNet" version="4.0.3.12153". We have logged a bug for this and will fix it in next update of this package.

 

namespace MyApplication
{
    using System.Collections.Generic;
    using DotNetOpenAuth.OpenId.Extensions.AttributeExchange;
    using DotNetOpenAuth.OpenId.RelyingParty;
 
    /// <summary>
    /// Represents Google OpenID client.
    /// </summary>
    public class GoogleCustomClient : OpenIdClient
    {
        #region Constructors and Destructors
 
        public GoogleCustomClient()
            : base("google", WellKnownProviders.Google) { }
 
        #endregion
 
        #region Methods
 
        /// <summary>
        /// Gets the extra data obtained from the response message when authentication is successful.
        /// </summary>
        /// <param name="response">
        /// The response message. 
        /// </param>
        /// <returns>A dictionary of profile data; or null if no data is available.</returns>
        protected override Dictionary<string, string> GetExtraData(IAuthenticationResponse response)
        {
            FetchResponse fetchResponse = response.GetExtension<FetchResponse>();
            if (fetchResponse != null)
            {
                var extraData = new Dictionary<string, string>();
                extraData.Add("email", fetchResponse.GetAttributeValue(WellKnownAttributes.Contact.Email));
                extraData.Add("country", fetchResponse.GetAttributeValue(WellKnownAttributes.Contact.HomeAddress.Country));
                extraData.Add("firstName", fetchResponse.GetAttributeValue(WellKnownAttributes.Name.First));
                extraData.Add("lastName", fetchResponse.GetAttributeValue(WellKnownAttributes.Name.Last));
 
                return extraData;
            }
 
            return null;
        }
 
        /// <summary>
        /// Called just before the authentication request is sent to service provider.
        /// </summary>
        /// <param name="request">
        /// The request. 
        /// </param>
        protected override void OnBeforeSendingAuthenticationRequest(IAuthenticationRequest request)
        {
            // Attribute Exchange extensions
            var fetchRequest = new FetchRequest();
            fetchRequest.Attributes.AddRequired(WellKnownAttributes.Contact.Email);
            fetchRequest.Attributes.AddRequired(WellKnownAttributes.Contact.HomeAddress.Country);
            fetchRequest.Attributes.AddRequired(WellKnownAttributes.Name.First);
            fetchRequest.Attributes.AddRequired(WellKnownAttributes.Name.Last);
 
            request.AddExtension(fetchRequest);
        }
 
        #endregion
    }
}

 

Source Code for existing providers

The source code for existing providers is public and can be accessed at https://github.com/AArnott/dotnetopenid/tree/master/src/DotNetOpenAuth.AspNet/Clients

Register your provider with your application

WebForms

  • In App_Start/AuthConfig.cs register the custom provider as follows
OpenAuth.AuthenticationClients.Add("Custom Google", () => new MyApplication.GoogleCustomClient());
//OpenAuth.AuthenticationClients.AddGoogle();
   

MVC

  • In App_Start/AuthConfig.cs register the custom provider as follows

 OAuthWebSecurity.RegisterClient(new MyApplication.GoogleCustomClient(),"Google",null);
           // OAuthWebSecurity.RegisterGoogleClient();

WebPages

  • In _AppStart.cshtml register the custom provider as follows

 

 OAuthWebSecurity.RegisterClient(new MyApplication.GoogleCustomClient(),"Google",null);
           // OAuthWebSecurity.RegisterGoogleClient();
Leave a Comment
  • Please add 7 and 6 and type the answer here:
  • Post
  • So, let me see if I understand correctly. Out of the box you can't provide a list of scopes/permissions in the AuthConfig file? You must create your own provider? If this is the case, how you specify additional scopes is not clear to me in the above code. What am I missing?

  • I wish this article were named better. The real question behind custom providers is how to implement someone Microsoft didn't include out of the box. This doesn't explain that at all.

  • @Shawn, yes I agree this article does not quite explain what you are specifically looking for. you should look at github.com/.../IAuthenticationClient.cs

    which is what all our providers(facebook, google etc) implement. to write your own you can inherit from IAuthenticationClient and override the 2 methods and roll your own system

  • @J.R. for this release yes out of the box there is no way to specify scopes and permissions. we can look into making it easier to specify in the future

  • Hi Pranav,

    I have recently upgraded to VS2012 (after years with 08/10) and I am attempting a facebook based web app, and your posts are invaluable, so firstly thank you.

    After researching for a few days I am little bit stuck on best practice, and I wondered if you could help me with a couple quick question(s) regarding storing "extradata" for future use after external login.

    In "ProcessProviderResult", after a valid external login, I need at least a the User.Identity.Name / Membershipusername, but during debug, after the call -

    if (OpenAuth.Login(authResult.Provider, authResult.ProviderUserId, createPersistentCookie: false))

               {

    The User.Identity... does not have a username and is not authenticated until after the page redirects?

    Q1) Is this expected behaviour, am I seeing something incorrect? how can I get hold of logged in username?

    Q2) Is the source code to the Microsoft.AspNet.Membership.OpenAuth available anywhere?

    Apologies if I have missed something simple, I am nearly there but not quite ...

    NOTES

    I "think" (have not retested lots) have also noted a truncation error when trying to create new long user names (i.e. auto-generated by facebook)

    AND if you set requiresUniqueEmail="true" you cannot get passed the create user for external login.

    May be useful if the templates get updated?

    Thanks

    Matt

  • @Matt I will try to answer as best as I can

    q1: this is expected

    User.Identity.Name is available when the user is authenticated by oauth provider. the oauth login is a 2 step process where we get the token first and authenitcate the user with the token and get data back from the oauth provider

    q2: source code is not yet public. we are working on it.

    what would you like to see updated in the templates?

  • How i can get email from facebook & twitter request. I have already provided the permission for email for my facebook app. please suggest how i can add the scope parameter in facebook request with the email field permission.

  • Hi Pranav,

    Has this been fixed in ASP.NET and Web Tools 2012.2 Release recently announced by Scott Guthrie?

    weblogs.asp.net/.../announcing-the-asp-net-and-web-tools-2012-2-release-candidate.aspx

  • @Mark, this it not yet fixed

  • As of December 2013 (DotNetOpenAuth.AspNet 4.3.3.13295) this is still not fixed.

  • You GitHub link is not working. Please provide the correct link.

Page 1 of 1 (11 items)