ASP.NET apps using OWIN permit multiple Identity sources (Facebook, Google, etc.). Most of the provider-specifc information those sources provide is irrelevant to my app, potentially even large, and I don't want it in my cookies all session. My app is primarily WebAPI, but I suspect the question applies equally to MVC and WebForms.
For now, all I need is an integer account ID. Where/when should I reconstruct the identity, after external authentication?
For example, here is one way I could filter claims:
public ReplaceExistingClaims(ClaimsIdentity identity) {
{
Claim customClaim = GetCustomClaimFromDbForIdentity(identity);
foreach (Claim claim in ClaimsIdentity.Claims) ClaimsIdentity.RemoveClaim(claim);
ClaimsIdentity.AddClaim(customClaim);
}
And following are two different places I could inject those claims changes:
var facebookAuthenticationOptions = new FacebookAuthenticationOptions
{
Provider = new FacebookAuthenticationProvider
{
OnAuthenticated = context =>
{
ReplaceExistingClaims(context.Identity);
return Task.FromResult(0);
}
}
};
Above, I know I can hook an individual provider from Startup
IF it provides an Authenticated
event. I have two conceptual problems with this. One: it requires me to write and wire up my code separately for each provider I plug in. Two: there is no requirement for providers to provide this event. Both of these make me feel like there must be a different intended insertion point for my code.
public ActionResult ExternalLoginCallback(string returnUrl)
{
ReplaceExistingClaims((ClaimsIdentity)User.Identity);
new RedirectResult(returnUrl);
}
Above, I know I can put code in ExternalLoginCallback
. But this happens too late for two reasons. One: The user has already been issued a ticket I consider invalid, but the default [Authorized]
considers valid because it's signed by me, and now they are making requests to my site with it. There could even be race conditions here. Two: There is no guarantee the browser will visit this redirect, and I'd prefer from a design perspective if it didn't have to, e.g. to simplify my WebAPI client code.
To the best of my knowledge, the best solution will meet these requirements:
- same code applies to all providers
- client receives my custom ticket from my server (e.g. without image claims)
- client never receives another ticket format from my server
- the authentication process requires the minimum possible HTTP round-trips
- token-refresh and other core identity features are still available
- once a user is
[Authorize]
d, no further account transformation is necessary - database/repository access is feasible during ticket generation
Some pages I'm researching, for my own notes:
- How do I access Microsoft.Owin.Security.xyz OnAuthenticated context AddClaims values?
- https://katanaproject.codeplex.com/SourceControl/latest#src/Microsoft.Owin.Security.Facebook/FacebookAuthenticationHandler.cs
- https://katanaproject.codeplex.com/workitem/82
- https://www.simple-talk.com/dotnet/.net-framework/creating-custom-oauth-middleware-for-mvc-5/