5

I'm developing an API for an application I'm working on and I've come across an interesting question:

Imagine an API endpoint like this:

GET /customers/123456

which returns a single customer object. Now, in our organization, customers can belong to sales organizations. Each API user is associated with an organization and I want to restrict a user's access to customers associated with their organization.

So, given a user who belongs to organization ABC and customer 123456 who belongs to organization XYZ, what should my API return when this user attempts to get that customer?

  • 404 Not Found - if a user queries a non-existent customer, it returns a 404 since no resource was found at that URL.

  • 401 Unauthorized - if you query a resource to which you do not have access, you should get an "unauthorized" response.

It seems to me that if the API returns 401 Unauthorized or existing customers from other organizations and 404 Not Found for non-existent customers, my API is leaking information. For example, a user from organization ABC could query the API and determine which user IDs exist and which don't.

Additional notes:

  1. Customer IDs are generated sequentially and there are no gaps, so the type of information that would be leaking would be:

    • what will the next customer ID be?
    • how many customers were created in a time period?
  2. The sales organizations are generally restricted to particular geographic areas and are not usually in direct competition. But some territories do overlap and there are rules in effect to govern "poaching" each other's customers. So, all in all, it's a mildly competitive environment where we don't really want sales organizations to know about each other's clients.

7

First off, if these user IDs are actually sensitive information as you say, do not put them directly in the URL. Why not just make opaque URLs instead and solve the problem before it even occurs? If you remove the relationship between the URL and the user(s), it will be next to impossible to deduce any relationships from a returned status code.

For example, instead of:

GET somepath/customers/123456

just implement some sort of small hashing system with a 2-way look up table and you can use a different URL such as:

GET somepath/DC884298C70C41798ABE9052DC69CAEE

Sure, this takes a bit more work, but if you are legitimately concerned about the issue, it's really a trivial implementation.

Back to your actual question, the W3C states that if someone attempts to access a resource, but is not properly authenticated, then it is OK to return 404, rather than 403 (Forbidden):

If the server does not wish to make this information available to the client, the status code 404 (Not Found) can be used instead.

By the same logic, I don't see why it wouldn't be fine to return 404 instead of 401 if the client is authenticated but not authorized. But keep in mind that, with this approach, someone who is actually trying to work with your API may be confused and just assume that the resource doesn't exist and not realize that they just don't have sufficient authorization. This is ultimately up to you to decide. I will say that, in my experience, I have seen both methods implemented before. If you do choose to return a 404, make sure that you specify this somewhere in your API docs so that other developers are aware.

Source: https://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html#sec10.4.4

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.