Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Set cookie from Web Api 2 IAuthenticationFilter AuthenticateAsync method

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).

like image 914
Maxime Rossini Avatar asked Dec 14 '25 06:12

Maxime Rossini


1 Answers

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);

}
like image 76
Hugh Jeffner Avatar answered Dec 15 '25 20:12

Hugh Jeffner



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!