2

In the context of POST/PUT endpoints, is it ok to retrieve the id from the authentication token instead of forcing the user to send it via a path variable?

For example, PUT /api/users that updates the logged-in user's info would arguably be more convenient for clients than PUT /api/users/{id}. Assuming, of course, the said token contains a userid claim.

Another idea is to have a forwarding endpoint: PUT /api/users would forward to PUT /api/users/{id} passing the userid claim.

6
  • This question is similar to: REST API design: POST (implicit userId) vs PUT (explicit userId). If you believe it’s different, please edit the question, make it clear how it’s different and/or how the answers on that question are not helpful for your problem. Commented Jun 2 at 21:10
  • 3
    this is the second time you've asked basically the same thing "how do i make my users endpoint RESTful?" I feel like we are human chat GPTs for your essay Commented Jun 2 at 21:27
  • 2
    @Ewan were not we always? The goal of StackExchange is to provide searchable answers to a wide range of questions, mostly the same as LLM with similar quality. Commented Jun 2 at 22:17
  • 8
    Also, the site is dying, so if we had no Sergey, we would have to invent one, to spice thing up anyway. Commented Jun 2 at 22:23
  • 3
    At the very least it would probably be something like /api/me or /api/users/me (or self or current or whatever...) rather that /api/users. Commented Jun 3 at 10:56

3 Answers 3

34

REST gives you a lot of discretion to define the resources that make sense for your application. The problem I've always had with api/users/{id} is that it looks like any user can update any user. For security-related stuff, I've always liked a pseudo resource like api/current-user or api/users/current with the implication that you do not pass a resource Id in the URL; instead the resource Id is derived from a JWT or session cookie. This cements your REST API into "the current user" with no apparent workaround.

There is still the issue of admin users in your system whose job is to modify other users. For that use case, I like api/users/{id} where "normal" users get a 403 Forbidden response to any request to that endpoint.

I'm not citing a best practice here. I just like separation of resources along the lines of "things normal users can do to their own user profile" and "things admins can do to any user's profile." It's not so much a REST thing as it is a way to organize these into distinct endpoints that follow their own rules. I wouldn't want a change to how admins can manage users to affect how users can manage their own information, and vice-versa.

9
  • I do like the clear separation. In fact, I would make it even more explicit and have part of the path be public (unauthenticated traffic), private (authenticated traffic), or admin (administration traffic) so no mix-up is possible. Commented Jun 3 at 12:55
  • @MatthieuM. And then your business rules changes and you have to clean up a mess of paths 😅 . Commented Jun 3 at 14:22
  • 2
    @DavidMulder: I could see public-vs-private being blurry -- specifically, I could public endpoints becoming private -- but opening admin endpoints to the general public is a terrible idea in general, security-wise: you're better off redoing a new endpoint from scratch. Commented Jun 3 at 14:24
  • 2
    @GregBurghardt I don't have a problem with /api/users/current . Even have done it myself, although I guess in a perfect world one might not do it. It did end up in the same codepath though as admin level user updates (just an if id equals 'current' then id = currentUserId). My comment was purely in response to Matthieu M's comment with which I did strongly disagree. Commented Jun 3 at 15:06
  • 1
    @AaronDufour - you would be absolutely correct. I updated my answer. The description of a 401 is "unauthorized" when they really meant "unauthenticated". At least, to me, unauthorized means you are authenticated, but you lack permission. Commented Jun 4 at 12:10
3

If you just use the URL you have no security

If you just use the token you can't be an admin and update other users. (although "/updateMe" is a good option to keep the role check out of the business logic)

If you don't use the ID in the URL, you should use POST instead of PUT to avoid deliberately violating the HTTP spec (as previously discussed in this question)

IDs in the URL path can add other problems, such as for logs and metrics. Your best option is to POST the full object including the ID along with an auth token which includes a userId claim with no ID in the URL.

Now

  1. You can check the id and other claims in the token and compare to the object in the body to allow/deny/override the request as per your logic
  2. you allow both update me, and update other user uses
  3. You don't have userIds popping up in unexpected places in your logs
  4. Your endpoint metrics have low cardalinity
  5. your POST request is fully REST and HTTP compliant
  6. your object contains all the fields, so you don't have to combine or split data from/into different parts of the request
3
  • With best option, would a POST to create another user just omit the id? If so, is the risk of accidental omission of id(e.g. due to bug) resulting in creating new users rather than updating the existing one acceptable (I think so, but just wondering)? Commented Jun 4 at 9:56
  • it branches off into another topic ie. "should the object have an id before its persisted?" I think the general agreement is that it should, and so you use guids and have the client set the id, which means you can always include it. If you let the sever create the id, then sure, you can leave it null and return it, or have a CreateObjectRequest object with different properties or whatever Commented Jun 4 at 10:25
  • I think i would separate the create and update endpoints in either case as I would expect different business logic to be applied Commented Jun 4 at 10:27
-1

is it ok...

So I'm going to reframe this somewhat:

  • is it consistent with the REST architectural style?
  • is it consistent with the current HTTP specification?

And the answer to both of these is "no".

The REST architectural style is a collection of architectural constraints. One of those constraints is Uniform Interface; see section 5.1.5, and the follow ups in section 5.2, of Fielding's dissertation.

But very loosely: one of the important ideas is that all of us understand the semantics of HTTP requests the same way; it doesn't matter whether we're talking about a web log, or an e-commerce site, or an aggregation of fun cat videos, or a technical question/answer forum, or an API -- the messages have the same meanings, so we can use the same general purpose tools (browsers, web crawlers) to talk to any of them.

Similarly, we can stick various forms of general purpose components (caches, proxies) in front of the servers, and it all "just works", because everybody understands the messages the same way.

Now, on the web (which is the reference application of the REST architectural style), our messages are defined by the HTTP standards (currently RFC 9110, etc). And that means, among other things, when we want to identify the target resource of an HTTP request, then there's a set of rules about doing that which are shared by everybody that speaks HTTP.

Those rules vary somewhat for the different versions of HTTP, but since everybody shares those rules about different versions, it all works out. For example, the rules about HTTP 1.1 are here. You can read them to fully appreciate their technical glory, but the digest version is that the target resource is (in the common case) determined by looking at the Host header field and the request-target from the request line... and that's it.

So the fundamental problem with having a special rule for your server that part of the resource identifier is supposed to be encoded within the Authorization header field is: general purpose components aren't going to know about your special rules, and are going to continue to assume that you are using the same request semantics as everybody else.

And if something goes wrong - expensively wrong with lawyers and so on being called in - your lawyers are going to be very unhappy when they learn that your resource identifiers weren't following the same rules as everybody else.

The "good" news is that the likelihood of that happening is small. So you (and your clients) probably won't get burned badly.

4
  • 2
    "[Y]our lawyers are going to be very unhappy when they learn that your resource identifiers weren't following the same rules as everybody else." 🤨 There's no need for fear mongering. If lawyers got mad about weird APIs our profession would have been outlawed years ago. Commented Jun 3 at 15:44
  • 3
    I down-voted because you're reading way too much into this simple question. It's common practice to use multiple parts of an HTTP request (e.g., cookies and headers) to decide how to respond. And unless your API is your service, you have no legal or business obligations for it to work in any particular way. There are certainly good reasons to follow API standards, but it's not because you're going to get sued if some third-party proxy has trouble with it. Commented Jun 3 at 15:51
  • 2
    And even if the API is the service, you can't sue for bad API design—god I wish! Commented Jun 3 at 15:53
  • "but the digest version is that the target resource is (in the common case) determined by looking at the Host header field and the request-target from the request line... and that's it." I'm not sure I buy this. This would seem to imply that you someone's e.g. home page and what they are able to access can't be based on their user identity in REST. At the very least I think you need to provide more evidence of this assertion. Commented Jun 4 at 17:37

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.