Using Web Api 2.2, I have a custom IAuthenticationFilter that I use for authenticating client requests with a custom scheme.
Basically, when a client is not authenticated and wants to access a protected resource, he sends an Authorization header: Authorization: MyCustomScheme XXXXXXX alongside the request. The filter then validates the credentials, authenticates the user and generates a stateless authentication token for further access (similar to a JWT).
I would like to store the resulting authentication token in a cookie. When present in incoming requests, the cookie is locally validated in a separate filter (which is not presented here).
My problem is that if I try to set the cookie like this:
Task IAuthenticationFilter.AuthenticateAsync(HttpAuthenticationContext context, CancellationToken cancellationToken)
{
if (context.Request.Headers.Authorization != null &&
string.Equals(context.Request.Headers.Authorization.Scheme, "MyCustomScheme", StringComparison.OrdinalIgnoreCase))
{
// This works
CustomPrincipal principal = this.ValidateCredentials(context.Request.Headers.Authorization.Parameter);
context.Principal = principal;
// This doesn't work: context.ActionContext.Response is null
var cookie = new CookieHeaderValue("MySessionCookie", principal.AuthenticationToken) { Path = "/", HttpOnly = true };
context.ActionContext.Response.Headers.AddCookies(new CookieHeaderValue[] { cookie });
}
return Task.FromResult(0);
}
Then it fails because context.ActionContext.Response is null. How do I add a cookie to the response from within AuthenticateAsync?
See related: Setting Cookie values in HttpAuthenticationContext for IAuthenticationFilter (you can see in the comments that people experience the same issue).
My requirements were to add a header but it should be easy to adapt to add a cookie.
I took a different approach on this. I put the header I wanted to add into context.Request.Properties. Then in ChallengeAsync (it gets called for every request regardless) via a IHttpActionResult I check for the presence of the property and if it exists add it to the headers. Something like this:
protected class AddRenewOnAauthorizedResult : IHttpActionResult {
public const string RenewalPropertyKey = "ETicket.RenewalKey";
public AddRenewOnAauthorizedResult(HttpRequestMessage request, IHttpActionResult innerResult) {
this.Request = request;
this.InnerResult = innerResult;
}
public HttpRequestMessage Request { get; set; }
public IHttpActionResult InnerResult { get; set; }
public async Task<HttpResponseMessage> ExecuteAsync(CancellationToken cancellationToken) {
HttpResponseMessage response = await this.InnerResult.ExecuteAsync(cancellationToken);
if (Request.Properties.ContainsKey(RenewalPropertyKey)) Request.response.Headers.Add("X-ETicket-Renew", Request.Properties(RenewalPropertyKey));
Return response;
}
}
Then in ChallengeAsync:
public Threading.Tasks.Task ChallengeAsync(HttpAuthenticationChallengeContext context, Threading.CancellationToken cancellationToken)
{
context.Result = new AddRenewOnAauthorizedResult(context.Request, context.Result);
return Task.FromResult(0);
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With