If you’re using the Windows Azure Access Control Service (or any other STS for that matter) this is an issue you might encounter when your Web Role has more than one instance:
[CryptographicException: Key not valid for use in specified state.]
System.Security.Cryptography.ProtectedData.Unprotect(Byte encryptedData, Byte optionalEntropy, DataProtectionScope scope) +450
Microsoft.IdentityModel.Web.ProtectedDataCookieTransform.Decode(Byte encoded) +150
As explained in the Windows Azure Training Kit this is caused by the DPAPI:
What does ServiceConfigurationCreated do?
By default WIF SessionTokens use DPAPI to protect the content of Cookies that it sends to the client, however DPAPI is not available in Windows Azure hence you must use an alternative mechanism. In this case, we rely on RsaEncryptionCookieTransform, which we use for encrypting the cookies with the same certificate we are using for SSL in our website.
Over a year ago I blogged about this issue but that solution applies to .NET 3.5/4.0 with Visual Studio 2010. Let’s take a look at how you can solve this issue when you’re working in .NET 4.5.
Creating a certificate
So the the first thing you’ll need to do is create a certificate and upload it to your Cloud Service. The easiest way to do this is to start IIS locally and go to the Server Certificates:
Now click the Create Self-Signed Certificate option, fill in the name, press OK, right click the new certificate and choose “Export…“. The next you’ll need to do is go to the Windows Azure Portal and upload the certificate in the Cloud Service. This is possible by opening the Cloud Service and uploading the file in the Certificates tab:
Copy the thumbprint and add it to the certificates of your Web Role. This is possible by double clicking the Web Role in Visual Studio and going to the Certificates tab:
As a result the certificate will be installed on all instances of that Web Role. Finally open the web.config of your web application and add a reference to the certificate under the system.identityModel.services element:
Creating the SessionSecurityTokenHandler
The last thing we need to do is create a SessionSecurityTokenHandler which uses the certificate. To get started add a reference to the following assemblies:
Once you added the required references you can add the following code to your Global.asax file:
This code replaces the current security token handler with a new SessionSecurityTokenHandler which uses the certificate we uploaded to the portal. As of now, all instances will use the same certificate to encrypt and decrypt the authentication session cookie.