0

I have Widget entities that belong to Company entities. There is a one-to-many relationship between Companies and Widgets.

Here's my first pass at the Get method:

[Route("MyApi/Companies/{companyId}/WidgetAdministration/[controller]")]
[HttpGet("{widgetId}")]
public async Task<ActionResult<WidgetDTO>> GetWidget([FromRoute] int companyId, [FromRoute]int widgetId)
{
    WidgetDTO widgetDto = await _myContext.Widgets
        .Where(w => w.CompanyId == companyId && w.WidgetId == widgetId)
        .AsNoTracking()
        .ProjectTo<WidgetDTO>(_mapper.ConfigurationProvider)
        .FirstOrDefaultAsync();

    if (widgetDto == null)
    {
        return NotFound();
    }
    else
    {
        return Ok(widgetDto);
    }
}

if a user associated to "Company 1" requests "Company 1 Widget 55", but "Widget 55" belongs to "Company 2", what should I return?

404/NotFound - Since "Widget 55" belongs to "Company 2", the above LINQ statement will not find anything, even though "Widget 55" really does exist.

401/NotAuthorized - Since "Widget 55" does not belong to "Company 1", "Company 1" is not authorized to see it.

400/BadRequest - This is just a bad request, because the Widget and Company do not match.

As an aside, can anyone recommend a good resource to help me with other similar scenarios?

Joe
  • 1,091
  • 1
  • 11
  • 23
  • 1
    For security purposes, I think I would have each company use a different URL. The let URL permissions handle the errors. – jdweng Apr 27 '20 at 17:45
  • 1
    401 should only be returned if authorization fails, which is not the case here. So this clearly not the way. The two others are often harder to decide between: 404 is if the resource doesn’t exist, 400 is when the input is malformed or invalid. 404 seems to be the most reasonable and most specific one. – ckuri Apr 27 '20 at 18:28
  • 1
    See also [HTTP 1.1 specification](https://tools.ietf.org/html/rfc7231#section-6.5) which states that 400 is “the server cannot or will not process the request” because of e.g. “malformed request syntax, invalid request message framing, or deceptive request routing.” 404 is “the server did not find current representation […] or is not willing to disclose that one exists”. Technically you did process the request as you didn’t find anything wrong with it, which resulted in the representation of the resource not being found. – ckuri Apr 27 '20 at 18:44
  • @jdweng Not a bad idea, but for these use cases, it might be a little overkill. – Joe Apr 27 '20 at 19:28
  • @ckuri Thanks for the input, I was thinking 401/NotAuthorized because Company 1 should not be authorized to view Company 2's widgets. I think we're going with 404 due to srk's answer. – Joe Apr 27 '20 at 19:30
  • I do not know if you can stop the firewall from doing its work. – jdweng Apr 27 '20 at 19:54

2 Answers2

2

I would return a 404 for two reasons:

  1. In my mind, the 404 refers not to Widget/55, but to the entire resource URI: Company/1/Widget/55. This resource does not exist.
  2. A 403 prevents Company 1 from viewing Company 2's widgets, but it does expose the fact that Widget/55 exists. That may or may not be acceptable to you. According to the World Wide Web Consortium (W3C), "if the server does not wish to make this information available to the client, the status code 404 (Not Found) can be used instead."
srk
  • 1,625
  • 1
  • 10
  • 26
  • Thanks, point#1 is an excellent point. Also, using 404 instead of 403 does add a little bit of security, but that's kinda overkill for our use cases... but it makes it a little easier on the Front-End developers. – Joe Apr 28 '20 at 14:58
0

If you use 403, you will be disclosing secure information since we are declaring that the resource exists but you can't view it, thereby verifying the resource's existence.

Read more about confusing HTTP status codes here.