API security best practices matter more than client-side hardening because the API is where your data actually lives. Anyone can inspect a mobile app or a browser bundle, extract the endpoints, and call them directly with whatever parameters they choose. Security enforced in the client is therefore not security at all. This guide covers the controls that hold at the server layer: authentication, per-resource authorisation, input validation, rate limiting, and monitoring, along with the specific failures that cause the majority of real API breaches.
Getting Authentication and Token Handling Right
Authentication answers who is calling, and weaknesses here undermine everything built above them. The common problems are not exotic. Long-lived tokens that never expire, secrets embedded in client applications, and refresh mechanisms that allow indefinite session extension all appear regularly in production systems. None require sophisticated attack techniques to exploit, which is why they account for a disproportionate share of incidents relative to how straightforward they are to prevent.
Issuing Short-Lived Access Tokens
Access tokens should expire quickly, limiting the window in which a stolen token is useful. Pair them with refresh tokens that can be revoked centrally when an account is compromised.
Rotating Refresh Tokens on Use
Issue a new refresh token each time one is exchanged and invalidate the previous one. Reuse of a consumed refresh token indicates theft and should terminate the session entirely.
Never Embedding Secrets in Clients
Anything shipped in a mobile binary or browser bundle is readable. Client secrets, API keys with privileged scope, and signing keys belong on servers you control, never in distributed code.
Choosing Standards Over Custom Schemes
Established protocols have been examined by far more people than any in-house design. Implementing OAuth correctly is safer than a bespoke token scheme that has never been reviewed.
Enforcing Authentication on Every Endpoint
Endpoints added quickly for internal or debugging purposes routinely ship without authentication. Audit the full route list rather than assuming the middleware covers everything.
Enforcing Authorisation Per Resource
The single most common serious API vulnerability is not authentication failure but authorisation failure: a properly authenticated user accessing records belonging to someone else. It happens because the endpoint verifies that the caller is logged in, then trusts the identifier in the request to determine which record to return. Changing that identifier returns another userβs data. Preventing this requires checking ownership on every request rather than relying on the client to send only its own identifiers.
Verifying Ownership on Every Request
For each resource accessed, confirm server-side that the authenticated user is entitled to it. Never infer entitlement from the identifier supplied in the request.
Avoiding Predictable Identifiers
Sequential numeric identifiers make enumeration trivial once one vulnerability exists. Non-sequential identifiers do not replace authorisation checks but reduce the damage when one is missed.
Applying Field-Level Restrictions
Users entitled to a record are not necessarily entitled to every field on it. Filter responses by role rather than returning the full object and hiding fields in the interface.
Checking Authorisation on Write Operations
Read endpoints receive more scrutiny than write endpoints, yet unauthorised updates and deletions cause more damage. Apply the same ownership verification to every mutating operation.
Testing Authorisation Systematically
Automated tests attempting cross-account access on every endpoint catch these gaps reliably. Including this in API development test suites prevents regression as endpoints multiply.
Validating Input and Controlling Data Exposure
APIs accept whatever is sent to them, and treating that input as trustworthy is the root of injection vulnerabilities and unexpected behaviour. The corresponding output-side problem is returning more data than the consumer needs, on the assumption that the client will only display the relevant portion. Both stem from the same misconception, that the client constrains what happens, when in reality anything the API accepts or returns is fully under the callerβs observation and control.
Validating Against Explicit Schemas
Define what each endpoint accepts, including types, ranges, and formats, and reject anything that does not conform. Allowlist validation is considerably safer than attempting to filter known-bad input.
Using Parameterised Queries Throughout
Never construct database queries by string concatenation with user input. Parameterisation eliminates injection at the mechanism level rather than relying on sanitisation that can be bypassed.
Returning Only Required Fields
Excessive data exposure occurs when endpoints return complete objects and leave filtering to the client. Shape responses server-side to contain only what the consumer legitimately needs.
Constraining Query Complexity
Flexible query languages allow expensive nested requests that exhaust server resources. Depth limits and cost analysis matter particularly when weighing REST vs GraphQL for a public interface.
Handling Errors Without Leaking Detail
Stack traces, database messages, and framework versions in error responses assist attackers. Return generic messages externally while logging full detail internally for diagnosis.
Rate Limiting, Monitoring, and Response
Controls that prevent misuse and controls that detect it are different problems, and both are required. Rate limiting protects availability and slows credential stuffing and enumeration. Monitoring tells you when something unusual is happening, which is the only way most breaches are discovered before the data appears elsewhere. Neither is difficult to implement, but both are commonly deferred because they address risks that have not yet materialised, which is precisely when they need to be in place.
Applying Limits Per Identity and Endpoint
Global limits are too coarse. Apply per-user, per-IP, and per-endpoint thresholds so that expensive or sensitive operations are constrained more tightly than routine reads.
Protecting Authentication Endpoints Specifically
Login, password reset, and token exchange endpoints attract automated attacks. Stricter limits and progressive delays on these routes prevent credential stuffing from succeeding at scale.
Logging Enough to Reconstruct Events
Record who called what, when, and with what outcome. Investigating an incident without adequate logs means guessing at scope, which usually forces you to assume the worst.
Alerting on Behavioural Anomalies
Sudden volume changes, unusual access patterns, and spikes in authorisation failures indicate probing. Automated alerts on these signals shorten the gap between compromise and detection considerably.
Testing Defences Before Attackers Do
Scheduled penetration testing through app security services validates that controls work as intended rather than as documented.
Frequently Asked Questions
What is the most common API vulnerability?
Broken object level authorisation: an authenticated user accessing records belonging to another user by changing an identifier in the request. It occurs when endpoints verify login status but trust the supplied identifier to determine which record to return.
Is HTTPS enough to secure an API?
No. Transport encryption protects data in transit but does nothing about authorisation flaws, injection, excessive data exposure, or abuse. An API served entirely over HTTPS can still return any userβs records to any authenticated caller.
How should API keys be stored?
Server-side only, in a secrets manager or environment configuration, never in client applications or source control. Keys shipped in mobile binaries or browser bundles are readable by anyone who downloads the application.
Do internal APIs need the same security?
Yes. Network position is not a security control, and internal services are reachable once any component is compromised. Applying authentication and authorisation between internal services limits how far an initial breach can spread.
How often should APIs be security tested?
Continuously through automated tests in the build pipeline, with scheduled manual testing at least annually and after significant architectural changes. Endpoint counts grow steadily, and each addition is an opportunity for a control to be missed.
What is the difference between authentication and authorisation?
Authentication establishes who is calling. Authorisation determines what that caller may access. Most serious API breaches involve correct authentication combined with absent or incorrect authorisation, which is why the second requires checking on every individual request.


