Friday, 30 March 2012

Cross-Domain Forms Authentication with ASP.NET

I'm looking into splitting bits of a web application across multiple domains, so that - for example - all logins, password changes, etc. are handled at http://security.example.com/, payments and order history are handled at http://accounts.example.com/ and so on. Just to keep things interesting, some of these apps are in .NET 2.0 and some are greenfield apps we'll be building in .NET 4.0.

Good news is - it's completely possible. And with IIS 7, it's apparently even possible to secure static pages, classic ASP and other non-.NET pages using the same authentication mechanism.

Step 1: Make sure your machineKey values are identical

Each application that's going to participate in cross-domain authentication needs an identical machineKey element - this defines the encryption keys that are used to encrypt and decrypt the .ASPXAUTH cookie that contains the authenticated user data.

In my solution, I generated a machineKey using http://aspnetresources.com/tools/machineKey and then added this to the web.config files for each application individually - it goes under <system.web> like:

<system.web>
    <machineKey validationKey="yada yada yada" decryptionKey="yada yada yada" validation="SHA1" decryption="AES" />
</system.web>

In theory, you could also define this in your machine.config or machine-level web.config file - remembering that you may have up to four of these (x86 .NET 20, x86 .NET 4.0, x64 .NET 2.0 and x64 .NET 4.0) - but I haven't tested this approach.

Step 2: Configure your FormsAuthentication attributes

Add this to the <system.web> section of the applications that are going to participate in cross-domain authentication:

<authentication mode="Forms">
    <forms loginUrl="
https://security.example.com/login" timeout="2880" domain=".example.com" path="/" />
</authentication>

Key points to note here:

  • The loginUrl is an absolute reference to the site that hosts your security app - so if you try to view a secure page, it'll redirect you to this website to log in.
  • The cookie domain is set to ".example.com" = notice the leading dot. That's important - it means the same cookie will be sent to example.com, something.example.com, another.url.at.example.com, and so on.

You'll need to make sure you're calling FormsAuthentication.SetAuthCookie(username) on your login server, but once that's done, you should be able to retrieve HttpContext.Current.User.Identity.Name from anywhere on any participating server. It is still up to you to verify that the username is valid and authorized - but this should save you a bit of plumbing when it comes to getting things working.

2 comments:

Chris Collinson said...

Hi Dylan, Hows tricks? Interesting post. I like these sort of examples. I guess this creates a single sign on capability across the sites. Often a requirement these days with clients. Glad to see some asp.net 4 areas aren't breaking changes. Been hit by a few that are. Eg, site running under .net 4 suddenly breaking because MS decided to do Request Validation differently. Easy to fix but annoying non the less.

Anonymous said...

Exactly what I was looking for. Thanks much!!!