Development is iterative, we take that for granted. But iterations can be painful, excrutiating chop jobs where you rip the very heart and soul out of your product, only to replace it with something bigger, better, and stronger. Ally's authentication platorm went through a process like this, and while it was painful and took way longer than it should have or anyone would have liked it to, ultimately it was the best thing for the company.
Let me start by saying, there are hundreds of ways to handle authentication in web services. There are RESTful ways, implicit ways, explicit ways, certificates, usernames, explicit tokens, SOAP tokens, and any variation of combination there of. The first iteration of the Ally Auth platform used explicit username tokens, everytime you made a call, you passed in a token that had a username and password. Your username and password was authenticated and roles were assigned to you. A few problems exist with this setup: first, every service you called to has to have a connection to either a shared auth service or a direct connection to the users database. Definitely not preferable if you're trying for a true seperation of duties SOA architecture. Secondly, and perhaps more painfully, every service had to either keep a mapping of users to roles, or in addition to a simple authentication with each request, had to do a role lookup. With caching and client side "cookies" you could mitigate the performance impact, but the design with inelegant and maybe even a little painful.
After contemplating this, we decided it wasn't right. This isn't how you're supposed to do things. More to the point, what if we want to integrate with onsite authentication stores, at some point? There's no way to do that with a system like this, it's just too inflexible. So, breaking the problem into two parts, we looked at a) how to address repeate authetication in an elegant manner against multiple services, and b) how to manage roles / authorizations in a not-ugly way.
Tokens solve the first issue. We moved to an Secure Token Service (STS) model whereby on the first call to any Ally service, the caller is redirected to an authentication service that requests username / password, and if correct supplies a signed and dated token that can be used for direct calls to the webservice. Even better, the same STS can grant impersonation tokens to Ally services, but more on that later. The token was simple, it merely indicated to a calling service that some sort of authentication had occurred, nothing more.
Claims were then attached to the Token. Here now, the beauty of the Token / Claim system comes into play. Instead of explicitly defining roles such as "ProjectManager" the token contains information about the user, his user ID, email address, company, etc. With this knowledge, the individual service can now do their own authorization, or store their own ACLs.
Getting back to the impersonation, say one service needs to call a seperate service, perhaps to update the company information. Every service can be programmed as though a user is directly calling that service, and all authorization can be done against a user's token. So instead of having to program foreward facing and backoffice services seperatly, a front-end service wishing to make a call to a backend service requests an impersonated token for the current calling user, then makes the call to the backend. This brings up an additional point of elegance, as now if we want to create a website that offers direct access for a user to that backend service, all the authorization work is done correctly, and there aren't two authorization schemes at work (one for users directly calling, one for sevices calling).
If you want to learn more, check out the Geneva framework from Microsoft, it's what we're using (with WCF) and it is seriously cool.