Most API security advice guards the front door with authentication, rate limits, and a WAF. Then the breach comes through a door that was already unlocked: an endpoint that authenticates you correctly and then hands over data that was never yours. This is a practical, OWASP-mapped list of the practices that actually matter, written by an offensive security team that breaks APIs for a living, ordered by how often each failure shows up in real compromise.
Planck Defense · Offensive Security Team · September 1, 2026 · 11 min read
By Berk Dusunur, Founder & CEO, Planck Defense & Aerospace
The short version
API security is really access-control engineering. Authenticate strictly, but spend most of your effort on authorization: verify on the server, for every request, that this caller may reach this object and this function. Whitelist writable fields, validate input, rate-limit everything, keep an exact endpoint inventory, and then test authorization continuously, because the flaws that breach APIs (BOLA and BFLA) are the ones scanners cannot see.
API security is the practice of protecting application programming interfaces from misuse and attack across their entire lifecycle, from design and authentication through authorization, input handling, rate limiting, inventory, monitoring, and testing. Because an API exposes your business logic and data directly, with no browser and no human in the loop, an attacker can call it a million times a minute and reason about every parameter. That changes the threat model: the perimeter controls that protect a web app matter far less than whether each individual request is correctly authorized.
Here is the fact that should reorganize your priorities. According to the OWASP API Security Top 10 (2023), the top two risks by real-world impact are broken object level authorization and broken function level authorization, not injection, not misconfiguration. Most serious API breaches are authorization failures. So a best-practices list that spends ten items on the perimeter and one on authorization has the ratio exactly backwards. The list below fixes that.
Best practices only make sense against the threats they stop. These are the flaw classes that matter, mapped to the OWASP API Security Top 10 so you can cross-reference your own program.
| Risk (OWASP API 2023) | What goes wrong | Impact |
|---|---|---|
| API1 · BOLA / IDOR | Endpoint does not verify the object belongs to the caller | Read or modify other users' data |
| API2 · Broken authentication | Weak, forgeable, or non-expiring tokens; broken login flows | Account takeover |
| API3 · BOPLA / mass assignment | Caller writes object properties they should not control | Privilege or ownership takeover, price tampering |
| API4 · Unrestricted resource consumption | No rate limits, quotas, or size caps | Denial of service, cost blowups, brute force |
| API5 · BFLA | Server does not check role before running a function | A normal user reaches admin actions |
| API6 · Sensitive business flow abuse | Automation abuses a legitimate flow at scale | Fraud, scalping, spam |
| API7 · SSRF | Server fetches an attacker-supplied URL | Internal network and metadata access |
| API8 · Security misconfiguration | Permissive CORS, verbose errors, missing headers | Info leak, wider attack surface |
| API9 · Improper inventory management | Shadow, zombie, and deprecated endpoints | Unmonitored, unpatched entry points |
| API10 · Unsafe consumption of APIs | Blindly trusting third-party API responses | Injection and compromise via a partner |
Twelve controls, ordered roughly by how often their absence appears in real API compromise. The first two are the ones almost every breached API got wrong.
For every request that references an object by identifier (/orders/124, /users/89/profile, an ID in a query string or JSON body), the server must verify that the authenticated caller owns or is permitted that specific object before acting. Do it server-side, from a trusted session identity, on a deny-by-default basis. Never rely on the identifier being hard to guess: UUIDs, hashes, and nested GraphQL references are all BOLA surface. This single control prevents the number one API risk.
Every privileged action must check the caller's role on the server, not in the UI. If the admin button is simply hidden but DELETE /users/89 still executes for a standard token, you have BFLA. Test method swaps on the same path (GET to DELETE), undocumented admin routes, and service methods the client was never meant to call. Authorization lives in the API, never in the client.
Use a standard protocol (OAuth 2.0 / OpenID Connect). Issue short-lived access tokens with the narrowest scope that works, rotate refresh tokens, and on every request validate the signature, issuer, audience, and expiry. Reject the alg: none JWT trick and unverified signatures outright. Authentication answers “who are you”; get it strict and boring so you can spend your real effort on authorization.
Never bind a request body straight onto your data model. Define an explicit allow-list of fields a caller may set, and drop everything else. Fields like ownerId, role, isAdmin, balance, and price should be server-controlled and never writable from the client. This closes broken object property level authorization (mass assignment), a common path to ownership takeover and price tampering.
ownerId straight from the body, so the caller took the object. A writable-field allow-list stops it.Validate every parameter for type, format, range, and length at the edge, driven by your OpenAPI schema. Constrain what you accept before it reaches business logic. Strong input validation is your baseline defense against injection and a natural fit if you already publish a spec, which becomes the contract you enforce.
Apply per-user, per-IP, and per-endpoint limits, plus quotas and payload-size caps. Rate limiting is not just anti-DoS: it blunts credential stuffing, object-ID enumeration, and business-flow abuse. Pay special attention to expensive endpoints and anything that fans out to a third party or a database.
You cannot secure an endpoint you have forgotten. Maintain an authoritative inventory of every API, version, and environment, and retire deprecated and undocumented (“shadow” and “zombie”) endpoints. Old /v1 routes and staging APIs exposed to the internet are frequent, unmonitored entry points. Your spec should match reality, and reality should have nothing extra.
Shape responses on the server to the fields a caller is entitled to, rather than returning the full object and filtering in the client. Excessive data exposure leaks personal data, tokens, and internal fields that fuel the next step of an attack. Keep sensitive values out of error messages and logs too.
Any endpoint that fetches a URL, imports from a link, or calls a webhook can be turned inward against your own network and cloud metadata service. Validate and allow-list outbound destinations, block internal ranges and link-local addresses, and never trust a third-party API's response as safe input. Treat the data you consume with the same suspicion as the data you receive.
Enforce TLS on every route with HSTS, disable weak ciphers, and never accept credentials or tokens over plaintext. Keep API keys and signing secrets in a managed secret store, rotate them, and scope them tightly. Encryption is table stakes, but a single plaintext path or leaked key undoes the rest of the list.
Log authentication and authorization decisions with enough context to answer “who accessed what” after the fact, and alert on the patterns that precede an authorization breach: a single account walking sequential object IDs, low-privilege tokens hitting admin routes, sudden spikes on a sensitive flow. Detection does not replace prevention, but it catches the abuse your controls missed.
This is the practice that ties the other eleven together, and the one most programs skip, because it is the hardest to automate. Authorization is not a setting you configure once; it is a property that breaks on the next pull request that adds an endpoint. The only way to keep it honest is to test it continuously, with real identities, across every operation. That is exactly where scanners fail and where an identity-aware, spec-driven pentest belongs. More on that next.
Keep this next to your pull-request template. If a change touches the API, every box should still be true.
Read that checklist again and notice which items a tool can verify for you. A scanner can flag a missing security header or an outdated TLS suite. It cannot tell you whether GET /orders/124 should be allowed for the account that asked, because authorization is relative to identity, and a signature engine sees one request, one response, one caller. The controls at the very top of the list, the ones that actually stop breaches, are the ones automated scanning is structurally blind to. That is why authorization flaws sail through CI and land in production.
Testing authorization properly means authenticating as more than one user and role, then, for every operation the API exposes, replaying one identity's requests as another and checking whether the server wrongly allows it. Done by hand across a real API, that is dozens or hundreds of operations times several role pairings, which is why it usually gets sampled rather than done. This is the exact shape of problem an agentic API penetration test is built for. You give it your OpenAPI spec and one token per role; it enumerates every operation, replays one role as another across the whole surface, probes parameters for injection and mass assignment, and, because it is an agentic pentester rather than a scanner, it does not stop at “this looks off.” It reproduces the exploit and reports it with the exact request and response that prove it, rated with a CVSS v3.1 vector, on every deploy rather than once a year.
Best practices one through eleven are how you build a secure API. Practice twelve, continuous authorization testing, is how you keep it secure as the code changes underneath you. For the deeper method, see API security testing and our engagement methodology.
API security is the practice of protecting application programming interfaces from misuse and attack across their whole lifecycle: authenticating callers, authorizing every request against the specific data and functions the caller should reach, validating input, limiting resource consumption, keeping an accurate inventory of every endpoint, and testing all of it continuously. Because APIs expose business logic and data directly, the highest-impact API risks are broken authorization flaws (BOLA and BFLA), not injection.
Enforce object-level authorization on every endpoint that references an object, enforce function and role level authorization on the server rather than in the UI, use short-lived scoped tokens with validated signatures, whitelist writable fields to stop mass assignment, validate all input against a schema, rate-limit every endpoint, maintain an accurate inventory with no shadow or deprecated endpoints, return only the data a caller needs, defend against SSRF on outbound calls, encrypt everything in transit, monitor for authorization anomalies, and test authorization continuously on every deploy.
Broken Object Level Authorization (BOLA), also called IDOR, is the number one risk in the OWASP API Security Top 10. It happens when an endpoint authenticates a user but does not verify that the specific object they request belongs to them, letting an attacker change an identifier and read or modify other users' data. Automated scanners cannot find it because authorization is relative to identity.
Authenticate as more than one user and role, then, for every operation the API exposes, replay one identity's requests as another to check object and function level authorization, probe every parameter for injection and mass assignment, and confirm rate limits. Scanners miss the authorization class, so effective testing is identity-aware and, ideally, continuous. An agentic API penetration test does this across every documented operation and proves each finding with the exact request and response.
A vulnerability scanner or DAST tool matches one request and one response against known signatures. The dominant API flaws, BOLA and BFLA, are only visible when you compare what one account can do against what another account should be allowed to do. That is a stateful, multi-identity comparison a signature engine cannot express, which is why authorization flaws pass automated scans and reach production.
The two authorization flaws at the top of this list, and why scanners cannot find either.
Read → GuideThe 2023 list explained, the reference every practice on this page maps to.
Read → GuideHow to test authorization on every operation, and prove each finding with an exploit.
Read →Give Operator your spec and a token per role. It replays one role as another across every operation, probes every parameter, and proves what it finds, on every deploy.