Implementing BrowserID SignIn with ASP.NET

By Peter Bromberg

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.

Popularity  (2424 Views)
Picture
Biography - Peter Bromberg
Peter Bromberg is a C# MVP, MCP, and .NET expert who has worked in banking, financial and telephony for over 20 years. Pete focuses exclusively on the .NET Platform, and currently develops SOA and other .NET applications for a Fortune 500 clientele. Peter enjoys producing digital photo collage with Maya,playing jazz flute, the beach, and fine wines. You can view Peter's UnBlog and IttyUrl sites. Follow Microsoft MVP
Create New Account
Article Discussion: Implementing BrowserID SignIn with ASP.NET
Peter Bromberg posted at Thursday, August 25, 2011 7:01 PM
Hassan Humayun replied to Peter Bromberg at Sunday, September 18, 2011 2:19 PM
Wonderful article , the only cons that i can see with this solution is , what if a users email is updated according to the browserID and later on user tries to use his old email to log in. I think thats gonna frustrate the user experience to fill the whole form again.
Another cons is that this approach is not secure if browser is shared between multiple users.

I wonder if a browserID has an expiry or not :)
Peter Bromberg replied to Hassan Humayun at Sunday, September 18, 2011 2:19 PM
You can provide a form for changing the default email. I know of no solution that cannot handle a changed email (username) without requiring the user to enter the information into a form.  If a browser is shared with multiple users you would have to provide a Log Out link that would delete the cookie.