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.
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.
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
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!
Am I missing something? Your examples don’t seem to match the source code???
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
Sorry, my bad.
I needed to add:
using FormsAuthenticationExtensions;
I’ve updated the post to explicitly mention this step. Sorry, I should have been clearer that they are extension methods.
Why?
Why not use a regular cookie to store meta-data?
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
what is equivalent to vb.net for below code
new FormsAuthentication().SetAuthCookie(user.UserId, true, ticketData);
I was in the process of creating this functionality using the same idea `NameValueCollection`. I shall use your implementation 🙂
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 ?
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.
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.
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?