0

I am trying to get a webhook setup with Xero working locally. I am using ngrok to allow xero to call my localhost. To get the webhook working I must correctly return the "intent to receive"

It seems to be working fine in that I can debug it and follow it through. However when I try to return 200 for success (hashes match) or 401 unauthorized (hashes don't match) the receiving Xero still doesn't accept it. All it says is: "Response contained a body"

According to the Xero webhook docs my endpoint must ensure:

  1. It uses HTTPS
  2. It responds within 5 seconds with a 200 O.K status code
  3. There is no body in the response
  4. There are no cookies in the response headers
  5. If the signature is invalid a 401 Unauthorised status code is returned

I have tried returning the code in various ways:

public IHttpActionResult WebHooks()
{
    //if hash check fails I tried these
    return Unauthorized();
    return Request.CreateResponse((int)HttpStatusCode.Unauthorized);
    return StatusCode(HttpStatusCode.Unauthorized);
    
    //if hash check matched I tried the following
    return Ok();
    return Request.CreateResponse((int)HttpStatusCode.OK);
    return StatusCode(HttpStatusCode.OK);
    
}

In seething desperation I also tried

public int WebHooks()
{
    //if hash check matches
    return 200;
    //if hash check fails
    return 401;
}

Thank you in advance for your help. I spent too long searching for an existing answer, but I couldn't find any. What am I doing wrong? As far as I can see my webapi should work.

ShrapNull
  • 1,090
  • 1
  • 9
  • 15

2 Answers2

2

Figured it out. This is what I did to get it working:

            if (hashedPayload != xeroSignature)
            {
                ControllerContext.HttpContext.Response.Clear();
                ControllerContext.HttpContext.Response.StatusCode = (int)HttpStatusCode.Unauthorized;
                ControllerContext.HttpContext.Response.End();
                return Content(string.Empty);
            }

            ControllerContext.HttpContext.Response.Clear();
            ControllerContext.HttpContext.Response.StatusCode = (int)HttpStatusCode.OK;
            return Content(string.Empty);
Jacob Alley
  • 767
  • 8
  • 34
  • In webapi controller, ControllerContext does not contain a definition for HttpContext. Are you using regular .net framework MVC controller, a web api controller or dotnet core? Thank you for your help by the way – ShrapNull Jul 17 '20 at 19:34
  • I think for your case HttpContext.Current.Response should work instead of ControllerContext.HttpContext. – Jacob Alley Jul 17 '20 at 20:38
  • anyway you wanna accept this answer? i see you gave me a shoutout in yours – Jacob Alley Jul 31 '20 at 18:26
  • I don't want to accept your answer because it wasn't the answer for my particular issue. – ShrapNull Aug 04 '20 at 09:24
0

Nothing I tried worked and my swear-jar overfloweth. I noticed through ngrok that the "intent to receive" would return a 302 (as opposed to 401) and then would redirect to Account/Login.

This led me down a rabbit hole to where I discovered the answer

To quote:

If you are adding asp.net WebApi inside asp.net MVC web site you probably want to respond unauthorized to some requests. But then ASP.NET infrastructure come into play and when you try to set response status code to HttpStatusCode.Unauthorized you will get 302 redirect to login page.

That was exactly the behaviour I saw. When I tried the webhook in a new webapi project with only one method - it worked. However I want to get it working in my MVC site. I added what this post suggested and it now works perfectly for me.

Many thanks to @Jacob Alley

ShrapNull
  • 1,090
  • 1
  • 9
  • 15