Designing an API well is the “structure” half of the job. Authenticating and authorizing correctly is the “access” half. The two are usually treated separately, but one without the other doesn’t hold up in production.
This is a short checklist for reviewing both sides: the API contract first, then the access rules.
1. Start with the API contract
On every API review, I start by checking these points:
- Nouns, not verbs.
/getAllCarsshould be/cars. The verb is already implicit in the HTTP method. - Don’t mix plural and singular across resources in the same API.
- Sub-resources make the relationship explicit in the URL:
/cars/1/drivers,/cars/1/drivers/2. - Idempotency: repeating the same operation should produce the same result. A
POSTthat creates a new resource on every retry is a problem waiting to happen. - Headers aren’t decoration. A lot of information should travel via
Content-TypeandAccept, not the query string or body. - Make it easy to consume with links. It doesn’t need to be full HATEOAS, but returning related links in the payload saves an extra round trip for whoever’s consuming it.
- Filtering, sorting, pagination, field selection. An API has to be flexible:
/cars?color=red,/cars?seats<2. Without that, the client ends up filtering on their side what the server should have filtered already. - Version the API. Breaking the contract without a version forces every consumer to break along with it.
- Use HTTP status codes correctly, always.
200for everything that “worked” and a generic400for everything that “didn’t” isn’t API design, it’s laziness.
That’s already close to an annotated checklist: a bad request/response example on one side, a good one on the other, item by item.
2. Separate authentication from authorization
OAuth 2.0 is the industry-standard protocol for authorization — not authentication. Treating the two as synonyms is a common mistake, and it’s not just semantics: an OAuth2 token says what the application can do on someone’s behalf, it doesn’t confirm who that person actually is.
A real point of concern, one that only shows up once the system is in production with real traffic, is latency. It’s easy, through careless design, to end up re-validating tokens twice — a duplicate check nobody asked for that gets expensive once multiplied across thousands of requests per minute.
JWT, meanwhile, isn’t a random token — it has structure: Header, Payload, and Signature, each encoded and concatenated with dots. Understanding that anatomy helps debug authentication issues without relying purely on trial and error.
3. Review the complete sequence
First the contract — a well-designed API, with clear rules for resources, filtering, and status codes. Then who can call that contract, and how — OAuth2 and JWT properly understood, without the confusion between authenticating and authorizing. The detail that separates someone who’s actually been burned by this in production from someone who only read the spec is exactly that duplicate token revalidation: small, invisible in dev, expensive at scale.