Security

API security: JWT storage, rate limiting and access checks

23 May 2024 · 9 min read · SmartCG

The hygiene minimum for any public API: how not to let brute force take the server down.

Storing JWT tokens

Never keep an access token in localStorage: any script injected into the page can read it. Send tokens in cookies with HttpOnly, Secure and SameSite=Strict flags, so JavaScript cannot reach them and CSRF has a structural barrier.

Rate limiting

Protection against password brute force and application-level floods. In NestJS this is @nestjs/throttler. We limit authentication endpoints hard — for example no more than five attempts per minute from one IP — and keep the limit for authenticated business endpoints generous enough not to break real workflows.

IDOR: the most common real vulnerability

Insecure Direct Object Reference. If you have /api/orders/123, you must verify that order 123 belongs to the authenticated user, on the server, every time. Otherwise anyone can iterate over IDs and download other companies' data. This is the vulnerability we find most often in custom B2B systems.

Two more that are easy to get wrong

  • Mass assignment: never bind a request body directly to a database model — a client should not be able to set role or balance by adding a field.
  • Secrets in the client: any key shipped in a bundle is public. Integrations that need a secret belong on the server, behind your own endpoint.

Why this is not "security theatre"

None of these steps is exotic. They are the difference between an API that survives a bored attacker and one that does not — and they are cheaper to add at design time than to retrofit after an incident.

Services involved

Read next

Want an API review with priorities instead of a scare list?

We check authentication, access rights, integrations and deployment, then tell you what to fix first and why.