1. Courses
  2. Developer Foundations
  3. Building APIs with Node.js
  4. Stop 4

40 minIntermediate

Who are you and what may you do?

The partner ordering API serves 1,800 shops, about 40 sales reps and Mangrove's admins. Every request must answer three questions in order: who is calling, what may this kind of user do, and is this shop's data theirs. This lesson turns those questions into status codes, tokens, NestJS guards, scoped queries and rate limits.

By the end you can

  • Choose between 401, 403 and 404 with a fixed order of checks, and say why another shop's order is a 404
  • Pick sessions or bearer tokens for the mobile Partner app and the web back office, and explain the revocation trade-off
  • List what an API must verify in a JWT (signature, algorithm, issuer, audience, expiry) and use a vetted library to do it
  • Enforce per-shop permission with a guard and a scoped query on every read and write
  • Rate limit per shop and per rep with @nestjs/throttler and shared Redis storage, answering 429 with Retry-After

The everyday picture

Think of a wholesale warehouse with a trade counter. At the door, a guard checks your trade card: is it real, is it yours, has it expired? That is authentication. At the counter, the clerk looks at what kind of card it is. A shop's staff card lets you collect orders but not cancel them; the owner's card can do both. That is a role check.

Then comes the check that matters most. You ask for "order 88413". The clerk does not fetch it and then look at the name on it. She looks only on the shelf for your shop. If it is not there, the answer is "we have nothing for you under that number", whether or not the order exists for someone else. A sales rep has a card that opens the shelves of the 45 or so shops he looks after, and only those. And if one shop sends a runner to the counter every ten seconds, the clerk asks them to wait a moment so other shops get served.

That counter is the partner API: a door check, a card-type check, a shelf check and a queue.

401, 403 or 404: one order of checks

Security essentials introduced (who are you?) and (may you do this, to this record?). In an API, both end in a status code that the Partner app branches on, so the codes must be predictable. The reliable way to get there is to run the checks in a fixed order and stop at the first one that fails.

  1. Is the token valid? No token, a bad signature, the wrong audience or an expired token all give 401 Unauthorized. The name is old and confusing: 401 means "not authenticated". Add a WWW-Authenticate: Bearer error="invalid_token" header (the format from RFC 6750), so the app knows to refresh its token or ask the user to log in again.
  2. Is the caller under the rate limit? If not, 429 Too Many Requests with Retry-After. More on this below.
  3. Does the role allow this action at all? A shop staff member calling "cancel order" gets 403 Forbidden. This check looks only at the user and the route. It never loads the order, so it reveals nothing about any order.
  4. Is the record inside the caller's shops? The query itself includes the caller's shops. If it finds nothing, the answer is 404 Not Found, the same answer as for an id that does not exist.
  5. Do the business rules allow it? Cancelling an order that the distribution centre has already picked is 409 Conflict, as in Designing an API people can use.

Why 404 and not 403 in step 4? A 403 says "this order exists, and it is not yours". Order ids in the partner API are sequential numbers, and about 4,000 partner orders are placed each week. With 403, anyone with a valid token could walk the ids and learn how many orders other shops place and when. With 404, the API gives the same answer for "someone else's" and "nobody's". The 403 in step 3 is safe, because it is the same for every order id.

GET /v1/orders/88413 1. Valid token? signature, iss, aud, exp 401 log in again 2. Under the limit? per shop or per rep 429 wait, retry 3. Role allows it? @Roles, no order loaded 403 not allowed 4. In your shops? scoped query finds it 404 not found 5. Rules allow it? e.g. not picked yet 409 wrong state Handler runs: 200
The first failing check decides the status code. Steps 1 to 3 never read an order, so they reveal nothing about it. Step 4 puts the caller's shops into the query, so another shop's order and a missing order look the same: 404.

Quick check

The Partner app sends a request with an access token that expired five minutes ago. The order it asks for belongs to the caller's own shop. What should the API answer?

Loading the rest of the lesson…