Implementing BrowserID SignIn with ASP.NET

Mozilla Labs has come up with BrowserID, https://browserid.org/ a new identification / authentication mechanism that shares some of the features of OpenId, but is vastly simpler and easier to use.

As a user of BrowserID, you confirm your email addresses once. Then, you can sign into any web site that supports BrowserID with just two clicks, and without having to fill in a single form field.

When you, as a user, encounter a BrowserID enabled web site and choose to log in, you are presented with a BrowserID dialog. If you do not have any email addresses verified through BrowserID, you will be asked to supply an email address and password. You then receive a verification email with a confirmation link in it, and you are done. You only need to do this one time, ever.



Subsequent to this, the BrowserID authentication dialog will show you the email addresses that you have registered, as in the image above. You pick one, and sign in. No password required. It's that simple. The site receives your verified email address and that is all they receive.  And really that is all you as a site operator need, because you can use this verified email as the key into your "Users" table in your database. Need more info? Look up their email and if it's not there, show them a Profile form to fill out, and save their information in your database using their email address as the primary key.

The code to implement this is relatively simple; the verification part should be done server-side and I have provided a C# BrowserId class to handle this. You do not want to use the client - side verification that BrowserId provides in their demo, because you are exposing yourself to potential hacking.

Let's look at the pieces, one by one:

<script src="https://browserid.org/include.js" type="text/javascript"></script>
<script type="text/javascript">
<!--
    function browserID() {
        navigator.id.getVerifiedEmail(function (assertion) {
             if (assertion) {
                 document.getElementById('browserid_assertion').value = assertion;
                 document.getElementById('browserid_form').submit();
            } else {
                 alert('Could not complete identification');
            }
        });
         return false;
    }
-->
</script>
</head>
<body>
   <form action="login.aspx" method="post" id="browserid_form" onSubmit="return browserID();">
   <div align="center">
   <h2 style="text-align: center">BrowserID Demo in ASP.NET</h2>
<input type="hidden" name="assertion" value="" id="browserid_assertion" />
<input type="submit" value="Sign In">
<asp:Label ID=lblMessage runat="server" />
</div>
</form>
</body>
</html>

The above client script points to https://browserid.org/include.js to load the standard browserid authentication script. The next script defines a BrowserID() function that implements the getVerifiedEmail function by passing the received browserid_assertion value and submitting the form. Processing is then transferred to the server side:

protected void Page_Load(object sender, EventArgs e)
{
    if (lblMessage.Text =="" && Request["assertion"] !=null)
    {
var audience = Request.Url.Host + ":" + Request.Url.Port.ToString();
var browID = new BrowserID.Net.BrowserId(audience, Request["assertion"]);
if (browID.verify_assertion())
{
    lblMessage.Text =browID.get_email();
    // At this point you could check your database to see if this person's email is there,
    // and if not, you could redirect them to a profile form where they can fill in a profile.
    // their verified email address is their username / key.
    // No providers, no OpenId, no oAuth, no facebook - Easy!
    // And you don't have to store any passwords, so you cannot be hacked.
}
else
{
     lblMessage.Text ="Identification failure";
}
    }

What I do above is ensure to only run the required code if the form has been posted and the assertion has been passed as a parameter. It instantiates my BrowserId class, passing in the audience (the host and port, if any - which should match that shown in the BrowserID login dialog), and the assertion value. The assertion is what comes back in the client-script getVerifiedEmail function, and which is set in the hidden field "browserid_assertion", so it gets posted along with any other form fields.

We then call the server-side verify_assertion method, and if successful, we get a verified email for the logged in user. At this point,  you could check your database to see if this person's email is there, and if not, you could redirect them to a profile form where they can fill in a profile. Their verified email address is their username / key. There are no providers, no OpenId, no oAuth, no facebook - Easy!  And you don't have to store any passwords, so you cannot be hacked.

Here is the code for my C# BrowserId class and a helper JsonData class. I used JSON.NET to handle the JSON manipulation.

using System;
using System.Collections.Generic;
using System.Collections.Specialized;
using System.Linq;
using System.Net;
using System.Web;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;

namespace BrowserID.Net
{
    public class BrowserId
    {
         public string Audience { get; set; }
        public string Assertion { get; set; }
         public string Email { get; set; }
        public string Validity { get; set; }
        public string Issuer { get; set; }

         private string PostRequest(string url, NameValueCollection data)
        {
            WebClient wc = new WebClient();
            byte[] b = wc.UploadValues(url, data);
            string s = System.Text.Encoding.UTF8.GetString(b);
             return s;
        }

         public BrowserId(string audience, string assertion)
         {
             this.Audience = audience;
             this.Assertion = assertion;
        }

        /*
         Send the assertion to the browserid.org server (this must be over HTTPS)
          The response is read to determine if the assertion is authentic
         */
         public bool VerifyAssertion()
        {
            NameValueCollection parameters = new NameValueCollection();
             parameters.Add("assertion", this.Assertion);
             parameters.Add("audience", this.Audience);
            string s=PostRequest("https://browserid.org/verify", parameters);
            JsonData obj=   JsonConvert.DeserializeObject<JsonData >(s);
             if(  obj.status=="okay")
             {
               this.Email  =  obj.email ;
               this.Validity = obj.validity;
                 this.Issuer = obj.issuer;
               return true;
             }
             else
             {
               return false;
             }
    
         }
    }

     public class JsonData
    {
         public string email { get; set; }
        public string status { get; set; }
        public string validity { get; set; }
        public string issuer { get; set; }
    }
}
That's all it takes to implement BrowserId on an ASP.NET site!  I predict that BrowserID will take off - big time!

NOTE: There is a bug in Internet Explorer which prevents it from correctly handling postMessage, a call to which is in the BrowserID include file, as well as in my BrowserId class. As of 9/18/2011 this has been fixed in the dev and beta channels but has not yet been propagated to the main https://browserid.org/verify  url. You can use the dev and beta urls until they get it there.

You can download the Visual Studio 2010 Solution here.

By Peter Bromberg   Popularity  (5004 Views)