I had the exact same requirement. I tried to get the MVC5 CookieAuthentication to work, but it wouldn't let me use my own cookie value. But, your WebAPI should not return a set-cookie. WebAPI should be RESTful, and require the client to pass a bearer token on every request.
So, here's my solution. The username and password are sent to an external API, which return a JSON Web Token. The token from the API is stored in a cookie. You could do that in JavaScript, or in an MVC Account controller. That cookie is checked by the MVC app, and if it exists, the cookie indicates proof that the user is logged in to the MVC app, too.
In JavaScript, you pull that token from the cookie, and add it to all requests to the API in the Authorization header as Bearer token. Also, the MVC app can use the value of the cookie (the token) to access all of the user's claims. To logout, just expire the cookie.
First, wire up the app to use Bearer token, with our custom provider
// Api controllers with an [Authorize] attribute will be validated with JWT
app.UseJwtBearerAuthentication(
new JwtBearerAuthenticationOptions
{
AllowedAudiences = audienceId.ToArray(),
IssuerSecurityTokenProviders = providers.ToArray(),
Provider = new CookieOAuthBearerProvider("MyCookieName")
{
LoginPath = new PathString("/Account/Login")
}
}
);
Now, I had to use a custom provider, because the Bearer token is stored in the cookie, not in the standard header. I also need to redirect to a login page, rather that simply issuing a 401.
public class CookieOAuthBearerProvider : IOAuthBearerAuthenticationProvider
{
public PathString LoginPath {get; set;}
public string CookieName { get; set; }
public CookieOAuthBearerProvider(string cookieName)
{
if(string.IsNullOrWhiteSpace(cookieName)) {
throw new ArgumentNullException("cookieName");
}
else {
this.CookieName = cookieName;
};
}
public Task ApplyChallenge(OAuthChallengeContext context)
{
if (this.LoginPath.HasValue)
{
context.Response.Redirect(this.LoginPath.Value);
}
return Task.FromResult<object>(null);
}
public Task RequestToken(OAuthRequestTokenContext context)
{
string token = context.Request.Cookies[this.CookieName];
if (!string.IsNullOrEmpty(token))
{
context.Token = token;
}
return Task.FromResult<object>(null);
}
public Task ValidateIdentity(OAuthValidateIdentityContext context)
{
// prove that the cookie token matches this site using context.Ticket.Identity
return Task.FromResult<object>(null);
}
}
Then, anywhere else in your MVC app, you can get the Claims by simply saying:
ClaimsPrincipal.Current