Tatham Oddie

Released: FormsAuthenticationExtensions

with 15 comments

What it does

Think about a common user table. You probably have a GUID for each user, but you want to show their full name and maybe their email address in the header of each page. This commonly ends up being an extra DB hit (albeit hopefully cached).

There is a better way though! A little known gem of the forms authentication infrastructure in .NET is that it lets you embed your own arbitrary data in the ticket. Unfortunately, setting this is quite hard – upwards of 15 lines of rather undiscoverable code.

Sounds like a perfect opportunity for another NuGet package.

How to get it

Library: Install-Package FormsAuthenticationExtensions

(if you’re not using NuGet already, start today)

Source code: formsauthext.codeplex.com

How to use it

Using this library, all you need to do is add:

 using FormsAuthenticationExtensions; 

then change:

 FormsAuthentication.SetAuthCookie(user.UserId, true); 

to:

 var ticketData = new NameValueCollection {
    { "name", user.FullName },
    { "emailAddress", user.EmailAddress }
 };
new FormsAuthentication().SetAuthCookie(user.UserId, true, ticketData);

Those values will now be encoded and persisted into the authentication ticket itself. No need to store it in any form of session state, custom cookies or extra DB calls.

To read the data out at a later time:

 var ticketData = ((FormsIdentity) User.Identity).Ticket.GetStructuredUserData();
var name = ticketData["name"];
var emailAddress = ticketData["emailAddress"];

If you want something even simpler, you can also just pass a string in:

 new FormsAuthentication().SetAuthCookie(user.UserId, true, "arbitrary string here"); 

and read it back via:

 var userData = ((FormsIdentity) User.Identity).Ticket.UserData; 

Things to Consider

Any information you store this way will live for as long as the ticket.

That can be quite a while if users are active on your application for long periods of time, or if you give out long-term persistent sessions.

Whenever one of the values stored in the ticket needs to change, all you need to do is call SetAuthCookie again with the new data and the cookie will be updated accordingly. In our user name / email address example, this is actually quite advantageous. If the user was to update their display name or email address, we’d just update the ticket with new values. This updated ticket would then be supplied for future requests. In web farm environments this is about as perfect as it gets – we don’t need to go back to the DB to load this information for each request, yet we don’t need to worry about invalidating the cache across machines. (Any form of shared, invalidatable cache in a web farm is generally bad.)

Size always matters.

The information you store this way is embedded in the forms ticket, which is then encrypted and sent back to the users browser. On every single request after this, that entire cookie gets sent back up the wire and decrypted. Storing any significant amount of data here is obviously going to be an issue. Keep it to absolutely no more than a few simple values.

Written by Tatham Oddie

April 4, 2011 at 16:19

15 Responses

Subscribe to comments with RSS.

  1. Cute, but it’s worth everyone remembering that the cookie is only generated on sign in. In, for example, an application where the user can update their display name, the change wouldn’t be reflected until the cookie is recreated.

    Harry M

    April 4, 2011 at 19:04

    • Hi Harry,

      Good catch. I’ve updated the post and Codeplex to mention this.

      In most cases though, I actually consider this behaviour to be an advantage. (As now noted in my explanation.)

      Thanks!

      – Tatham

      Tatham Oddie

      April 4, 2011 at 20:44

  2. Perfect timing, I was just going to implement my own solution to allow a couple of data points into the ticket. Clean implementation. Good job!

    Diego

    April 7, 2011 at 01:34

  3. Am I missing something? Your examples don’t seem to match the source code???

    Christian

    April 12, 2011 at 10:00

    • Hi Christian,

      The examples in the blog post show how to use the library. The source code on CodePlex is the code to the library itself.

      What’s not matching up for you?


      Tatham

      Tatham Oddie

      April 12, 2011 at 10:15

      • Sorry, my bad.

        I needed to add:
        using FormsAuthenticationExtensions;

        christian payne

        April 12, 2011 at 10:37

      • I’ve updated the post to explicitly mention this step. Sorry, I should have been clearer that they are extension methods.

        Tatham Oddie

        April 12, 2011 at 11:23

  4. Why?

    Why not use a regular cookie to store meta-data?

    Dave

    May 2, 2011 at 21:20

    • Hi Dave,

      1) Lifecycle management. Keeping a cookie with exactly the same lifetime as the authentication token is surprisingly tricky.

      2) Encryption. Anything you store in the ticket is encrypted and validated using ASP.NET managed cryptography. Good for storing internal user GUIDs and things like that which are best not to share if you don’t have to.


      Tatham

      Tatham Oddie

      May 2, 2011 at 22:24

  5. what is equivalent to vb.net for below code

    new FormsAuthentication().SetAuthCookie(user.UserId, true, ticketData);

    Azri Jamil

    July 17, 2011 at 04:01

  6. I was in the process of creating this functionality using the same idea `NameValueCollection`. I shall use your implementation :)

    Alexander Freiria

    September 15, 2011 at 01:45

  7. Why not to hold extra information that is related to user in session ? This is exactly what i am doing. Why i have to prefer this way instead of session solution ?

    Yakup İpek

    October 27, 2012 at 22:52

    • Session state is fine, if you have no more than one or two servers, sticky load balancers and aren’t aiming for high availability. I much prefer to design for the web as a stateless communication model, as it works under the covers, rather than try to rely on abstracted statefulness.

      Tatham Oddie

      January 29, 2013 at 21:05

  8. FYI this doesn’t work:

    new FormsAuthentication().SetAuthCookie(user.UserId, true, “arbitrary string here”);

    It conflicts with a static method of FormsAuthentication with the same signature and you get a compile error.

    tmenier

    January 25, 2013 at 08:09

    • Hmm. Maybe there’s something changed in 4.5. (Please note, this post is almost 2 years old now.)

      Until I get time to investigate myself, can you at least mention what framework you are building against?

      Tatham Oddie

      January 29, 2013 at 21:02


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 )

Connecting to %s

Follow

Get every new post delivered to your Inbox.

Join 28 other followers

%d bloggers like this: