APIs (application programming interfaces) are the connective tissue of modern software: every card payment, every third-party login and every system-to-system integration passes through one. That central role also makes them the primary attack vector. According to the OWASP API Security Top 10, the most exploited vulnerabilities are not exotic flaws but design errors in authorization and validation. Building a secure API is not about adding a security layer at the end; it means making the right architectural, authentication and access-control decisions from the very first endpoint.
REST and GraphQL: when to use each
The choice of architectural style shapes the security model. REST organizes the API around resources identified by URL and HTTP methods (GET, POST, PUT, DELETE), with a predictable attack surface: each endpoint protects one resource. GraphQL exposes a single endpoint over which the client composes flexible queries, reducing over-fetching but introducing its own risks — deeply nested queries can trigger denial of service if depth and complexity are not constrained.
| Aspect | REST | GraphQL |
|---|---|---|
| Endpoints | Multiple, one per resource | Single endpoint |
| Data fetching | Risk of over- or under-fetching | Client requests exactly what it needs |
| HTTP caching | Native and straightforward | Complex (everything is POST) |
| Characteristic risk | Unauthorized exposed endpoints | Deep and expensive queries |
Authentication versus authorization: they are not the same
Confusing the two concepts is the root cause of many breaches. Authentication answers "who are you?" while authorization answers "what are you allowed to do?". The reference standard for delegating access is OAuth 2.0 (RFC 6749), which allows an application to access resources on behalf of the user without handling their password, using access tokens. Built on top of OAuth 2.0 is OpenID Connect, which adds an identity layer (establishing who the user is, not just what they can do).
For server-side application flows the Authorization Code Flow is used, and for public clients (SPAs and mobile apps) this is supplemented with PKCE (Proof Key for Code Exchange, RFC 7636), which prevents interception of the authorization code. Tokens are typically implemented as JWTs (JSON Web Tokens): signed tokens the server can validate without querying a database. Access tokens should be kept short-lived, with renewal delegated to longer-lived, revocable refresh tokens.
BOLA: the number one vulnerability
The top position in the OWASP API Security Top 10 is held by BOLA (Broken Object Level Authorization). It occurs when an endpoint verifies that the user is authenticated but does not verify that the requested object belongs to them. The classic example: GET /api/invoices/1043 correctly returns the invoice to its owner, but if another authenticated user changes the identifier to 1044 and receives a third party's invoice, the API has a serious BOLA vulnerability. The defence is to verify in every operation that the authenticated subject has permission over that specific object, and never to rely on a hard-to-guess identifier as the only form of protection.
Rate limiting and protection against abuse
Without rate limits, an API is exposed to credential brute-forcing, mass scraping and denial of service. Rate limiting restricts the number of requests per client within a time window. The most common algorithms are the token bucket (allows controlled bursts), the leaky bucket (smooths out the flow) and the sliding window. Good practice is to communicate limits via standard headers such as RateLimit-Limit and RateLimit-Remaining, and to respond with status 429 Too Many Requests accompanied by a Retry-After header when the threshold is exceeded.
Input validation and injection prevention
All client input is hostile until proven otherwise. Validation should apply an allowlist principle: explicitly define what is accepted (type, length, format, range) and reject everything else, rather than trying to filter out the bad. Database queries must always use parameterized statements to neutralize SQL injection, and output must be context-encoded to prevent XSS. Validating a request schema with tools such as JSON Schema or the OpenAPI specification makes it possible to reject malformed requests before they ever reach the business logic.
The API gateway: a single point of control
As the number of services grows, managing security endpoint by endpoint becomes unmanageable. An API gateway solves this by sitting in front of the services as a single entry point. It centralizes cross-cutting concerns that would otherwise need to be re-implemented in every service: TLS termination, token validation, rate limiting and quota enforcement, routing, request transformation and traffic logging. Concentrating these functions in the gateway eliminates duplication of security logic and, more importantly, eliminates inconsistencies: one place decides who can call what and at what frequency.
The gateway is also the natural place to apply the zero-trust model to internal communications. In modern microservice architectures, services authenticate each other using mTLS (mutual TLS), so each internal call verifies both the client's identity and the server's. Compromising a single service therefore does not grant free access to the rest of the system, because every hop continues to require valid credentials.
Webhook security
Webhooks reverse the usual flow: instead of the client polling the API, the server notifies the client when an event occurs. This presents a different risk, because the receiver exposes a public endpoint that anyone could invoke. The standard defence is signature verification: the sender computes an HMAC of the message body using a shared secret and sends it in a header; the receiver recomputes the signature and compares it before processing anything. It is also advisable to include a timestamp in the signature to prevent replay attacks and to reject stale messages.
Steps for designing a secure API
- Enforce HTTPS on all endpoints; never accept plaintext traffic.
- Authenticate with OAuth 2.0 / OpenID Connect and short-lived tokens, avoiding static API keys embedded in clients.
- Authorize at object and function level on every request, applying the principle of least privilege.
- Validate all input against a schema and parameterize queries.
- Apply rate limiting and quotas per client, user and IP address.
- Version the API (
/v1/,/v2/) to evolve without breaking integrations. - Log and monitor access and anomalies, without dumping sensitive data into logs.
- Document with OpenAPI and keep the documentation synchronized with the code.
Common mistakes
The first is broken object level authorization (BOLA) as described above. The second is excessive data exposure: returning the full database object and trusting the client to display only the relevant fields, when an attacker inspects the raw response. The third is not limiting resources, leaving the API open to massive pagination requests or unlimited GraphQL queries. The fourth is poor secrets management: keys and tokens stored in source code or in repositories. The fifth, and very common, is the shadow or zombie API: endpoints from older versions that remain active without maintenance or protection.
Frequently asked questions
Which is better, an API key or OAuth 2.0? API keys identify an application but not a user, and they are difficult to rotate and revoke. OAuth 2.0 offers short-lived tokens, permission scopes and revocation. For user access, OAuth 2.0 with OpenID Connect is the recommended standard; API keys are appropriate for low-risk server-to-server integrations.
Is GraphQL less secure than REST? It is not inherently less secure, but it shifts the risk: with REST you guard each endpoint; with GraphQL you must limit query depth and complexity, apply operation allowlists and disable introspection in production.
Where should I store tokens in a web application? For SPAs, avoid localStorage because of its exposure to XSS; prefer HttpOnly, Secure and SameSite cookies, complemented with CSRF protection. For mobile apps, use the operating system's secure storage.
How often should I rotate credentials? Access tokens should expire within minutes or hours; client secrets and API keys should be rotated periodically and, without exception, whenever there is any suspicion of a leak, using an automated rotation process that causes no downtime.
Conclusion
API security is won or lost in the design of authorization, not in the strength of the encryption. The most telling insight from the OWASP API Security Top 10 is that the dominant failures (BOLA, broken function level authorization, excessive data exposure) are business logic errors that no automated tool can fully detect: they depend on verifying, in every operation, that this user can perform this action on this object. A modern API combines OAuth 2.0 with PKCE, short-lived tokens, strict schema validation, rate limiting and observability, all versioned and documented with OpenAPI. At Summum we design and integrate APIs applying this model from the very first endpoint, so that opening an integration to a third party does not mean opening a door into the rest of the system.