What is API security?

API security is the practice of protecting application programming interfaces from misuse and attack. Because an API exposes backend logic and data directly to any caller that can reach it, the discipline centres on authenticating every request, authorising access at the object and function level, constraining resource consumption, and keeping an accurate inventory of every endpoint.

The reference standard for this is the OWASP API Security Project, which publishes the API Security Top 10. It is deliberately separate from the general OWASP Top 10 because the risks that dominate an API surface are not the ones that dominate a rendered web page. Practical implementation guidance sits alongside it in the OWASP REST Security Cheat Sheet.

Why API security needs its own playbook

A traditional web application usually mediates access through a browser and a rendered page, which accidentally hides some mistakes from casual probing. An API does not have that layer. Every endpoint is a direct, machine-readable line into backend logic and data, called the same way by a legitimate mobile app, a partner integration, and an attacker's script.

That difference is why OWASP maintains a dedicated API Security Top 10, separate from the general OWASP Top 10. Object identifiers, business logic flows, resource consumption and third-party data all behave differently in an API context, and the practices below are organised around the risks that come up most often.

It also does not matter whether the API in question is REST or GraphQL. REST typically spreads authorisation logic across many endpoints, so a gap in one route is often contained. GraphQL usually exposes a single endpoint over a whole graph of data, which means a missing check at one resolver, or an unbounded query depth, can reach far further than a single REST route ever would. The practices below apply to both, but are worth testing deliberately against each.

The OWASP API Security Top 10 at a glance

Most recently updated in 2023, on a separate release cycle to the general OWASP Top 10. Each practice further down this page notes which risk category it primarily addresses. The full descriptions, with example attack scenarios for each category, are published as the 2023 edition.

CodeRisk
API1:2023Broken Object Level Authorization
API2:2023Broken Authentication
API3:2023Broken Object Property Level Authorization
API4:2023Unrestricted Resource Consumption
API5:2023Broken Function Level Authorization
API6:2023Unrestricted Access to Sensitive Business Flows
API7:2023Server Side Request Forgery
API8:2023Security Misconfiguration
API9:2023Improper Inventory Management
API10:2023Unsafe Consumption of APIs

Access control practices

Access control failures dominate the API Top 10, appearing in one form or another across half of its ten categories. Getting authentication and authorisation right is the single highest-leverage thing an API programme can do. The OWASP Authorization Cheat Sheet is the companion reference for the design decisions below.

1. Authenticate every call, every time

Addresses API2:2023 (Broken Authentication). Every endpoint that touches anything beyond genuinely public data needs a real authentication check, including internal service-to-service calls and endpoints added late that 'inherit' access from a gateway rule. Tokens should expire, be scoped narrowly, and be revocable without waiting for expiry. Long-lived, unscoped static API keys are the most common way this practice fails in real deployments.

2. Enforce authorisation at the object level

Addresses API1:2023 (Broken Object Level Authorization) and API3:2023 (Broken Object Property Level Authorization). Never trust an object ID in a URL or payload to imply the caller is allowed to see or edit that object. Check ownership or permission on every request, at the object level and at the individual field level, since a user allowed to view a record is not automatically allowed to view or edit every field on it.

The classic failure is sequential identifiers: a caller authorised for GET /api/v1/invoices/1041 changes the number to 1042 and receives another customer's invoice, because the handler looked up the record by ID and never asked whether this caller owns it. Replacing the integer with an unguessable identifier raises the effort slightly but fixes nothing; the ownership check is the fix.

3. Enforce authorisation at the function level

Addresses API5:2023 (Broken Function Level Authorization). Administrative and privileged endpoints need their own explicit permission checks, not an assumption that a user will not know the URL. This matters most where roles and hierarchies are complex: a support-tier account and an admin-tier account calling the same API base need different function-level checks enforced server-side.

Method matters as much as path. An endpoint that correctly refuses DELETE /api/v1/users/88 to a non-administrator, but accepts PATCH on the same path with a role field in the body, has a function-level gap even though the obvious route is protected.

A JWT validation checklist

Where bearer tokens are JSON Web Tokens, most real authentication failures are validation failures rather than cryptographic ones. The checks below are the minimum, and all of them belong server-side on every request, not once at a gateway.

  • Verify the signature before reading any claim. Claims in an unverified token are attacker-controlled data.
  • alg: pin the accepted algorithm server-side. Reject none, and reject any algorithm you did not expect.
  • kid: resolve a key identifier only against your own key set, never against a URL supplied inside the token.
  • iss: confirm the issuer is the authorisation server you actually trust.
  • aud: confirm the audience names this API, so a valid token minted for a different service is rejected.
  • exp and nbf: reject expired and not-yet-valid tokens, allowing only a small clock-skew margin.
  • sub and scope: map the subject to a local principal and check the scope covers this operation. A valid signature is authentication, not authorisation.

Scoping tokens: an OAuth example

Scopes describe what a token may do, not merely who it belongs to. An integration that only reads invoices should be issued a token carrying scope=invoices:read, and a call to a write endpoint using it should be refused even though the signature is perfectly valid.

The pattern to avoid is one broad scope, such as scope=api, handed to every client because it was simpler at integration time. At that point the token proves identity and nothing else, and every authorisation decision falls back to per-endpoint code that may not have been written. Narrow scopes give the API a second, independent place to say no.

Traffic and abuse controls

Correct authentication and authorisation do not stop a legitimate, authenticated caller from abusing an API at scale. That needs its own controls.

4. Rate limit and cap resource consumption

Addresses API4:2023 (Unrestricted Resource Consumption). Set limits on request rate, payload size, and any expensive operation (large exports, batch queries, file uploads), per client and per account, not just at a shared gateway level. Without this, a single authenticated client can drive a denial of service or run up operational cost.

Pagination limits belong in the same category. An endpoint that honours a client-supplied page size such as ?limit=100000 has handed control of database load to the caller; clamp the value server-side to a sane maximum rather than trusting it. For GraphQL, the equivalent controls are query depth and complexity limits, since a single request can otherwise expand into a very large amount of work.

5. Protect sensitive business flows from abuse

Addresses API6:2023 (Unrestricted Access to Sensitive Business Flows). Some flows are legitimate individually but harmful at scale: bulk account creation, coupon redemption, or ticket purchasing, for example. These need flow-specific controls, such as step-up verification or velocity checks, in addition to generic rate limiting.

Input, output and request handling

APIs accept structured input by design, which makes it easy to assume the structure alone makes it safe. It does not.

6. Validate input and encode output

The API-specific expression of Injection, which sits at A05:2025 on the OWASP Top 10. Validate type, length, format and range on every field, server-side, regardless of what client-side validation exists. Reject unexpected fields rather than silently dropping them, and encode output appropriately for wherever a response ends up rendered.

Rejecting unexpected fields is what closes mass assignment. If a registration endpoint binds the whole request body onto a user model, a caller who adds "role": "admin" to an otherwise ordinary payload may have it written straight through. An explicit allow-list of writable fields prevents this regardless of what the underlying framework does by default.

7. Validate and restrict server-side requests

Addresses API7:2023 (Server Side Request Forgery). Any endpoint that fetches a remote resource on the caller's behalf, a webhook target, an image URL, an import feed, needs to validate that URI against an allow-list rather than trusting whatever the client supplies. Otherwise a caller can direct the API to reach internal systems it should never be able to see.

Validate the resolved address, not just the string. A hostname that passes an allow-list check can still resolve to a private or link-local address, and the cloud instance metadata service at 169.254.169.254 is the usual target because it can return credentials. The OWASP SSRF Prevention Cheat Sheet sets out the address ranges to deny and the application-layer and network-layer controls that pair with them.

Inventory and lifecycle management

APIs tend to expose more endpoints than a traditional web front end, and they tend to outlive the documentation written for them. Both problems compound over time unless they are actively managed.

8. Maintain a live, accurate API inventory

Addresses API9:2023 (Improper Inventory Management). Keep a current inventory of every environment, every version, and every endpoint, including internal and partner-only APIs. Undocumented or forgotten 'shadow' endpoints, and old versions nobody decommissioned, are frequently the least monitored and least patched part of an API surface.

Generating the inventory from the running service, for example from an OpenAPI document produced by the application itself rather than maintained by hand, keeps it honest. A hand-written inventory records what the team believes is deployed, which is precisely the thing that drifts.

9. Version deliberately and retire old versions

A related but distinct discipline: publish a clear versioning scheme, communicate deprecation timelines, and actually decommission old versions rather than leaving them reachable indefinitely. A deprecated version that still accepts traffic keeps every vulnerability it ever had live, whether or not the current version fixed them.

This is worth testing rather than assuming. If /api/v2/orders is the current route, confirm that /api/v1/orders and any unversioned /api/orders alias actually refuse traffic, and that a non-production hostname is not quietly serving the same data with older code behind it.

10. Manage secrets and credentials properly

API keys, signing secrets and service credentials should never be committed to source control or embedded in a client application, mobile app or query string. Store them in a dedicated secrets store, inject them at runtime, and rotate them on a schedule and immediately on suspected exposure. This overlaps with API8:2023 (Security Misconfiguration), which covers the configuration side of the same problem. The OWASP Secrets Management Cheat Sheet covers centralisation, rotation and detection in more depth.

Putting a key in a query string is worth calling out separately, because a request to /api/v1/report?api_key=SECRET leaks that key into server access logs, proxy logs, browser history and any Referer header sent onward. Credentials belong in a header, not a URL.

Visibility and third-party risk

The final two practices are about what happens after a request lands, both the ones you receive and the ones your own API makes to other services.

11. Log and alert on abuse patterns

Logging every authentication attempt, authorisation failure and rate-limit trigger is only half the practice. The other half is wiring that logging to alerting so someone, or something, actually responds when a pattern looks like enumeration, credential stuffing or scraping, rather than the log sitting unread until an incident is already underway.

Log the decision, not the secret. A useful record captures the caller principal, the endpoint, the object identifier and the authorisation outcome; it must not capture the bearer token, API key or request body field that carried a credential, since that turns the log store into a second copy of everything worth stealing.

12. Treat third-party API responses as untrusted input

Addresses API10:2023 (Unsafe Consumption of APIs). Data returned from a third-party or partner API deserves the same validation as data submitted directly by a user. It is common for teams to apply weaker checks to responses from an API they consume than to their own inbound traffic, on the assumption that a partner's data is inherently safe.

Blind trust also extends to redirects and timeouts. Following redirects from an upstream service without re-validating the destination reintroduces the SSRF problem from practice 7, and an upstream call with no timeout or size limit lets a slow or oversized third-party response become your own availability incident.

Bringing the practices together

No single practice above substitutes for the others: an API with strong authorisation but no rate limiting is still exposed, and one with perfect input validation but a stale inventory is still carrying risk in the versions nobody is watching. Treat API security as a lifecycle rather than a one-off checklist: build the controls in at design time, verify them before release, and re-verify on a cadence as endpoints change.

That verification step is where a documented method matters. The OWASP Web Security Testing Guide provides the test-by-test structure, and NIST SP 800-115 provides the surrounding planning and reporting framework. Both push toward the same behaviour: check authentication and authorisation on every endpoint systematically, rather than sampling a handful and assuming the rest behave the same way.

It is worth revisiting the list after every meaningful change to an API, not only on a fixed annual schedule. A new endpoint, a new integration partner, or a new field added to an existing object can reopen an access control or validation gap that the last review closed, which is the same argument for continuous penetration testing applied specifically to a fast-moving API surface.

How PentestOps helps

PentestOps tests REST and GraphQL APIs directly, independent of any front-end client, against OWASP API Top 10 categories: broken object and function level authorisation, excessive data exposure, rate-limiting gaps and the rest of the list above. See API penetration testing for the detail.

Confirmed authorisation and injection findings are validated with safe, RoE-gated exploitation, with a live finding stream over WebSocket during the scan, rather than left as unverified detections. Reports map every finding to 8 compliance reporting frameworks (OWASP Top 10, PCI DSS v4.0, NIST 800-53, SOC 2, HIPAA, GDPR, ISO 27001, SMB1001) plus CIS Benchmarks for AWS, Azure, GCP and Kubernetes.

Pricing is asset-wise, with each API counted as an asset and scans unlimited within fair use. Run a free demo scan against your own API, or start a 7-day free trial; a card is required to start your trial and is only charged after the trial ends, unless you cancel first.

Frequently Asked Questions

What is the OWASP API Security Top 10?

A ranking of the ten most critical API-specific security risks, maintained separately from the general OWASP Top 10 on its own release cycle. It was most recently updated in 2023 and covers risks like broken object level authorisation and unrestricted resource consumption that behave differently in an API than in a traditional web page.

What is the difference between object-level and function-level authorisation?

Object-level authorisation checks whether a caller can access a specific record, such as another customer's order by ID. Function-level authorisation checks whether a caller can reach a specific action or endpoint at all, such as an administrative function. An API can fail either independently of the other.

How is API security different from general web application security?

An API exposes backend logic and data directly, without a browser rendering a page that might mask a mistake. It is also called by scripts, integrations and mobile apps as readily as by a legitimate browser session, which is why OWASP maintains a separate API Security Top 10 alongside the general OWASP Top 10.

What should a JWT validation check actually verify?

Verify the signature first, then the registered claims: a pinned algorithm rather than whatever the header requests, an issuer you trust, an audience naming this API, and expiry and not-before times with only a small clock-skew allowance. Then check that the token's scope covers the operation, because a valid signature proves authentication, not authorisation.

Do I still need rate limiting if my API already requires authentication?

Yes. Authentication confirms who is calling, not how much they are allowed to do. A legitimate, authenticated account can still be used, or compromised, to drive excessive calls, large exports, or expensive operations, which is exactly what unrestricted resource consumption (API4:2023) describes.

What is improper inventory management in API security?

It is the risk of old, undocumented, or forgotten API versions and endpoints staying reachable after they should have been retired or documented. These 'shadow' endpoints are typically the least monitored and least patched part of an API surface, since nobody is actively tracking them.

Should API keys be treated the same as passwords?

Yes, and often they deserve more care, since a leaked API key can grant programmatic access at scale. Keep them out of source control, client-side code and URL query strings, store them in a dedicated secrets store, scope them narrowly, and rotate them on a schedule and immediately on suspected exposure.

Is GraphQL harder to secure than REST?

It is different rather than strictly harder. REST spreads authorisation across many routes, so one gap is often contained. GraphQL exposes one endpoint over a whole data graph, so a missing check at a single resolver can reach much further, and query depth and complexity limits matter as much as rate limits do.

How does PentestOps test API security?

PentestOps tests REST and GraphQL APIs directly against OWASP API Top 10 categories, including authentication and authorisation testing at both the object and function level, with confirmed findings validated through safe, RoE-gated exploitation rather than left as unverified detections. See API penetration testing.

Put these practices to the test

Run a free demo scan against your API or start a 7-day free trial. A card is required to start your trial and is only charged after the trial ends, unless you cancel first.