bigonotes
System DesignAPI Design

Security Considerations

Authentication vs authorization, when to use API keys or JWTs, role-based access control, and rate limiting for APIs.

5 min readLast updated API Design

Every API has to answer two questions about each request: who is making it, and are they allowed to do this? It also has to protect itself from clients that send too much. In most interviews security isn't the focus, so a sentence or two is usually enough. But you should know what those sentences mean.

Authentication vs authorization#

These two words sound alike but answer different questions.

  • Authentication (AuthN) verifies identity: is this request really from john@example.com?
  • Authorization (AuthZ) verifies permission: is John allowed to cancel this booking? He can cancel his own bookings, not everyone's.

In an interview, say which endpoints require an authenticated user and that you'd use a JWT (or a session stored server-side) to identify them. Derive the current user from the token, never from a user_id in the request body.

API keys#

An API key is a long random string that works like a password for an application rather than a person.

  1. Generate a unique key per client, e.g. sk_live_abc123....
  2. Store it (ideally hashed) with that client's permissions and rate limits.
  3. On each request, look up the key and identify the client.
GET /events
Authorization: Bearer sk_live_abc123...

They're a good fit for server-to-server calls where you control both sides (the booking service calling the payment service) and for third-party developers who need programmatic access.

They're almost never right for end users. People shouldn't manage long secret strings, and API keys don't expire or carry user context the way a login session does.

JWT (JSON Web Token)#

A JWT is a signed JSON object that the server hands out at login and the client sends back on each request. Think of it like a passport: your identity is checked once, then you show the stamped passport, and anyone who trusts the seal accepts it without checking your birth certificate again.

Structure#

A JWT is three base64url-encoded parts joined by dots, header.payload.signature:

Part Contains Example
Header Token type and signing algorithm {"alg": "HS256", "typ": "JWT"}
Payload Claims: user id, roles, expiry {"sub": "12345", "name": "Alex", "admin": true, "exp": 1735689600}
Signature Signature over header and payload, made with the server's key Changes if any byte of the payload changes

The payload is encoded, not encrypted. Anyone can decode and read it, so never put passwords or sensitive data in it. Security comes from the signature: if an attacker flips "admin": false to true, the signature no longer matches and the server rejects the token.

Flow#

  1. Login: the client sends credentials.
  2. Issue: the server verifies them and signs a JWT. With HS256 it uses a shared secret; with RS256 it uses a private key, and services verify with the public key.
  3. Store: the client keeps the token, preferably in an HttpOnly cookie, or in app storage on mobile.
  4. Use: every request carries Authorization: Bearer <token> (or the cookie).
  5. Verify: the server checks the signature and expiry. No database lookup is needed, because the token itself carries the user's identity.

Why use JWTs#

  • Stateless: there's no session store to share. Any number of servers can verify tokens as long as they have the key, so the API tier scales horizontally.
  • Mobile-friendly: a token is just a string, so it works the same on iOS, Android and web.
  • Cross-service: one token can be accepted by several related services, which is the basis for single sign-on.

Edge cases#

Problem Mitigation
Token theft Short-lived access tokens (e.g. 15 minutes) plus refresh tokens
Data leakage Keep payloads lean, with no secrets or personal identifiers like SSNs
XSS stealing the token Store it in an HttpOnly cookie that JavaScript can't read
Revoking access Tokens are valid until they expire, so keep a denylist (e.g. in Redis) of revoked token ids for immediate logout

Rule of thumb: use API keys for internal services and external developers, and JWTs for user sessions in web and mobile apps.

Role-based access control (RBAC)#

Real systems have different kinds of users. In a ticketing system, customers book tickets and view their own bookings, venue managers create events and see sales for their venues, and admins can do everything. RBAC gives permissions to roles and roles to users, instead of granting permissions to each person.

Role Permissions
customer Book tickets, view own bookings
venue_manager Create events, view sales for own venues
admin Everything

Each user is then assigned a role:

User Role
john@example.com customer
manager@venue.com venue_manager

Each request then checks both. For GET /bookings/{id}:

  1. Authenticated? The request carries a valid JWT.
  2. Authorized? The user owns this booking, or the user's role is admin.

In an interview it's usually enough to say which roles can call which endpoints, and often the distinction doesn't matter at all.

Rate limiting and throttling#

Rate limiting caps how many requests a client can make in a time window. It protects against attacks, scrapers and accidental overload.

  • Per user: e.g. 1,000 requests per hour for each authenticated user.
  • Per IP: e.g. 100 requests per hour for unauthenticated traffic.
  • Per endpoint: e.g. 10 booking attempts per minute to slow down ticket scalpers.

Enforce limits at the API gateway or in middleware, and return 429 Too Many Requests when a limit is hit. Unless you're asked, don't design the algorithm (token bucket, sliding window). Saying "we'll rate limit at the gateway to prevent abuse" is usually enough.

Key takeaways#

  • Authentication answers "who are you?"; authorization answers "are you allowed?".
  • Use API keys for services and third-party developers, and JWTs for user sessions.
  • JWTs are signed, not encrypted. Keep them short-lived and stored in HttpOnly cookies, and plan for revocation.
  • RBAC grants permissions to roles, not individuals.
  • Rate limit at the gateway and return 429.

Found a mistake? Tell me on LinkedIn ↗

Further reading#