Vicedomini Softworks

Software Security

API Security Best Practices Developers Can Ship This Sprint

12 October 2026

Engineer checking API access controls at workstation

To secure APIs we must treat every request as untrusted: enforce TLS everywhere, issue short-lived identity tokens, validate authorisation inside the API itself, and place resource protections at the gateway. This approach aligns with guidance from NIST SP 800-228 and CISA, and the sections below translate each principle into concrete engineering steps.


TL;DR:

  • Use OAuth2 with OpenID Connect for third party, mobile, or delegated access; reserve narrowly scoped, rotated API keys over mutual TLS for controlled internal calls.
  • Keep access tokens valid for minutes, rotate refresh tokens after each use, and exchange tokens for narrower permissions instead of forwarding the user’s original token.
  • Apply rate limits per user, client, and IP, add payload and pagination caps, and use timeouts plus circuit breakers to contain resource exhaustion.
  • Validate requests against generated OpenAPI or gRPC schemas, reject unknown fields, inspect responses for sensitive data, and require schema checks in CI.
  • If APIs use browser cookies for sessions, set the SameSite attribute to Strict or Lax and add synchronizer tokens; bearer tokens in headers avoid cross site request forgery.

Vicedomini Softworks
Build APIs with security in mind
Vicedomini Softworks builds custom software with Zero Trust security, peer-reviewed code, targeted testing, and production monitoring.
Ask for a consultation

Table of Contents

Practical checklist: what to fix this sprint versus later

Not every control carries equal urgency. Some changes ship within a sprint; others demand cross-team coordination and architectural change.

Fast wins, typically achievable within days:

  • Enforce TLS 1.2 or higher on every endpoint, internal and external.
  • Add authentication middleware that validates tokens on every request, not only at the gateway.
  • Reduce access token lifetimes to minutes rather than hours.
  • Apply basic per-client rate limits at the gateway.

Slower, cross-team efforts:

  • Building a central API inventory with ownership tags.
  • Introducing schema validation across every service boundary.
  • Wiring telemetry into a SIEM for anomaly detection.

Unrestricted resource consumption remains a recognised API weakness class, and OWASP’s guidance recommends payload limits and rate limiting as baseline mitigations. Teams under time pressure should prioritise authentication, TLS and rate limiting first: these are the controls that stop the most common exploitation paths with the least engineering effort.

Implement authentication and enforce authorisation inside the API

OAuth2 combined with OpenID Connect (OIDC) is the appropriate choice whenever an API serves third-party clients, mobile applications, or any scenario requiring delegated access and identity federation. Simpler schemes, such as mutually agreed API keys over mTLS, remain acceptable for tightly controlled service-to-service calls within a single trust boundary, provided keys are rotated and scoped narrowly.

Authentication alone never proves a caller is permitted to act on a specific resource. Authorisation logic must live inside the API, not only at the perimeter. On every request we validate the token’s issuer, audience and signature, then check that the authenticated subject actually owns or is entitled to the resource being requested. Skipping that ownership check is how Broken Object Level Authorisation (BOLA) vulnerabilities appear, consistently cited as the leading weakness in OWASP’s API Top 10.

Scopes and claims give coarse-grained control (what an action a token permits), but attribute-based access control (ABAC) adds the finer layer: checking tenant ID, resource owner, or organisational hierarchy against the request context before returning data.

  • Validate issuer, audience and signature on every incoming token, not just at login.
  • Implement explicit ownership checks before returning or modifying any resource.
  • Write automated tests that attempt cross-tenant and cross-user access and assert denial.

Pro Tip: Write your BOLA test cases before writing the authorisation code: it forces you to enumerate every object relationship the API exposes.

TLS and transport security for every API endpoint

Transport Layer Security is non-negotiable for any API that carries authentication tokens, personal data, or business logic, internal services included. TLS 1.2 is the practical floor; TLS 1.3 where the stack supports it, with weak cipher suites and legacy protocol versions disabled entirely.

Certificate lifecycle management benefits from automation: short-lived certificates issued and rotated automatically reduce the operational risk of an expired or forgotten certificate taking down a production endpoint. For service-to-service calls inside a cluster or between trusted partners, mutual TLS (mTLS) adds client-side certificate verification, closing the gap left by one-way TLS.

  • Disable TLS versions below 1.2 and remove deprecated cipher suites from load balancer and gateway configuration.
  • Automate certificate issuance and renewal rather than relying on manual rotation schedules.
  • Apply mTLS for internal service-to-service traffic where the trust boundary justifies it.

TLS termination at the gateway simplifies certificate management but shifts trust onto the internal network; where that network cannot be fully trusted, re-encrypting traffic between the gateway and backend services closes the gap. The performance cost of TLS handshakes is largely mitigated by session resumption and connection pooling, so there is rarely a sound reason to leave an endpoint unencrypted.

Token lifecycle management and session protection

Access tokens should carry short lifetimes, typically minutes, to limit the damage a stolen token can cause. CISA’s implementation recommendations call for robust signature and issuer validation on every use, alongside telemetry that can detect misuse after the fact rather than relying solely on token validity. Refresh tokens should rotate on use, with old values invalidated immediately, and revocation lists checked on sensitive operations.

Delegation scenarios call for token exchange rather than forwarding a user’s original token to downstream services: each hop receives a narrower, purpose-specific token. NIST IR 8587 recommends documenting token lifetimes, validation steps and key management rather than treating token validity as the final word on access.

  • Issue access tokens with short lifetimes and rotate refresh tokens on every use.
  • Validate signature, issuer and audience claims on every request, not only at issuance.
  • Log SessionID and client context so that one-to-many access patterns, a common signature of token theft, surface during review.

Many breaches exploit stolen tokens rather than compromised credentials outright, which is why CISA’s guidance pairs token validation with telemetry correlation as a detection layer, not an optional extra.

Schema-driven validation and response hygiene

Defining the API contract with OpenAPI or a comparable interface definition language, then validating every request against it at the boundary, closes an entire class of injection and data-exposure vulnerabilities before they reach business logic. Unexpected fields are rejected rather than silently accepted, which removes a common path for mass-assignment errors.

Validation that stops at the request is only half the job. Responses deserve the same scrutiny: sensitive fields should be explicitly documented in the specification and stripped from any payload where they are not required, preventing the kind of accidental data leakage that turns a minor bug into a disclosure incident.

  • Validate every inbound request against the OpenAPI or gRPC contract and reject unknown fields.
  • Document sensitive response fields explicitly in the specification so reviewers can spot leakage.
  • Run schema validation as a required CI step, using generated validators rather than hand-written checks.

Pro Tip: Generate your request validators directly from the OpenAPI spec rather than maintaining them by hand: drift between the two is a recurring source of silent validation gaps.

Protecting resources: rate limits, timeouts and circuit breakers

Resource exhaustion is a recognised API weakness, and OWASP’s guidance on unrestricted resource consumption recommends payload size limits, maximum records per page, and rate limiting as the baseline response. Limits should apply per-user, per-client and per-IP, since a single dimension is trivially bypassed. Token-bucket or leaky-bucket algorithms handle bursty traffic more gracefully than fixed windows, and tiered services can apply adaptive limits that scale with a client’s plan.

Timeouts belong at both the TCP and application layers: a slow backend dependency should never be allowed to hold connections open indefinitely. Circuit breakers isolate a failing dependency before it cascades into a full outage, giving the system a controlled degraded mode instead of a collapse.

  • Apply per-user, per-client and per-IP rate limits using a token-bucket or leaky-bucket strategy.
  • Set TCP and application-level timeouts, and wrap backend calls in circuit breakers.
  • Monitor spend and call volume on third-party integrations, with hard caps where a runaway loop could generate real cost.

The API gateway and Zero Trust patterns for service calls

The gateway is the right place for coarse-grained enforcement: authentication, basic authorisation checks, rate limiting, WAF rules and request shaping. It is the wrong place to stop. Fine-grained authorisation, ownership checks and business-logic validation belong inside each service, because a gateway cannot know, for every request, whether the authenticated caller actually owns the specific resource being requested.

Zero Trust patterns extend this logic to service-to-service calls: mTLS between internal services, token exchange for delegated calls, and no implicit trust simply because traffic originated inside the perimeter. A common pitfall is relying on the gateway as the only enforcement point and assuming internal services are inherently safe once a request passes through it; that assumption is precisely what turns a single compromised service into a lateral-movement path.

  • Enforce authentication, rate limiting and WAF rules at the gateway.
  • Enforce ownership and fine-grained authorisation inside each service, never only at the edge.
  • Apply mTLS and token exchange for internal service-to-service calls rather than relying on network location as a trust signal.

Logging, monitoring and telemetry for detection

Effective detection starts with collecting security-relevant events as close to the authoritative source as practical. CISA’s logging reference architecture recommends preserving provenance and favouring event-driven delivery where timeliness matters, rather than batching logs that delay detection.

Each event should carry SessionID, ClientIP, a request ID and the calling application’s identity (AppID), giving analysts enough context to correlate activity across services without reconstructing it after the fact. Events should be normalised for correlation while retaining their original source context, since stripping that context too early removes evidence needed for forensics.

  • Capture SessionID, ClientIP, request ID and AppID on every authenticated request.
  • Favour event-driven log transport over batch delivery to shorten detection time.
  • Feed telemetry into a SIEM with detection rules tuned for anomalous one-to-many access patterns.

Correlating SessionID and ClientIP across services is how a single stolen token is often caught, a detection pattern CISA’s implementation guidance specifically recommends building into monitoring pipelines.

Secure-by-design lifecycle: inventory, DevSecOps and shift-left practices

An API nobody tracks is an API nobody secures. Maintaining a central inventory, tagged with owner, version and host, is the prerequisite for any serious vulnerability management programme; without it, shadow endpoints accumulate and quietly expand the attack surface. NIST SP 800-228 treats inventory discipline as foundational, alongside encryption, authentication and schema validation.

Shift-left practices move security checks earlier in the pipeline: static analysis (SAST), software composition analysis (SCA) for dependency vulnerabilities, and secrets scanning to catch credentials committed by mistake. Contract and schema tests belong in the same pipeline, catching breaking changes before they reach production.

  • Maintain a central API inventory with owner, version and host tagged for every endpoint.
  • Run SAST, SCA and secrets scanning on every pull request, not only at release time.
  • Include contract and schema tests in CI to catch breaking changes early.

An incremental, risk-based rollout works best in practice: basic runtime protections (authentication, rate limits, schema validation) across the whole estate first, with advanced payload inspection reserved for the highest-risk APIs where the engineering cost is justified.

Practical testing: CI checks, fuzzing and staged verification

A testing plan only works when it runs automatically and blocks merges, not when it depends on someone remembering to run it manually.

  1. Run contract tests and dependency scanning on every pull request.
  2. Schedule fuzzing and SAST runs nightly, or per-PR where build times allow.
  3. Commission penetration tests on a regular cadence, not only before major launches.
  4. Verify monitoring and alerting actively fire during canary releases, not just in theory.
  5. Keep a standing checklist of BOLA scenarios, cross-tenant access attempts, to test before every release.

Common mistakes and the fixes to apply

A handful of misconfigurations account for most incident post-mortems.

  • Long-lived tokens that outlive their usefulness: cut lifetimes to minutes and rotate refresh tokens on use.
  • Authorisation checked only at the gateway: push ownership checks into each service.
  • Missing schema validation: enforce the OpenAPI contract at the boundary and reject unknown fields.
  • No central API inventory: tag every endpoint with owner and version before the next audit.
  • Weak or absent logging: capture SessionID, ClientIP and request ID on every call.

Preventing cross-site request forgery in APIs

CSRF exploits the browser’s habit of automatically attaching credentials, typically cookies, to requests regardless of which site initiated them. APIs that rely on cookie-based session authentication are exposed to this risk; APIs that rely purely on bearer tokens sent in an Authorization header are not, because browsers do not attach that header automatically to cross-origin requests.

Where cookies remain in use for session management, the SameSite attribute set to “Strict” or “Lax” prevents the browser from sending the cookie on cross-site requests in most practical scenarios. A synchroniser token pattern, where the server issues a unique token bound to the session and the client must echo it back in the request body or a custom header, adds a second line of defence for state-changing operations such as POST, PUT and DELETE.

CORS configuration deserves scrutiny here too: a permissive Access-Control-Allow-Origin header combined with credentialed requests effectively invites the kind of cross-origin abuse CSRF protections exist to prevent. Restricting allowed origins explicitly, rather than reflecting the request’s origin back unchecked, closes that gap.

The most reliable path for new API designs is to avoid cookie-based authentication for cross-origin calls entirely, favouring bearer tokens in headers, which sidesteps the CSRF threat model rather than mitigating it after the fact.

Strategies for protecting against replay attacks

A replay attack reuses a previously valid, intercepted request, often including a legitimate token, to repeat an action the attacker has no right to trigger again. The defence starts with the same short token lifetimes already recommended for general token hygiene: a narrow validity window shrinks the usable window for a replayed request to almost nothing.

Nonces add a second layer: a unique, single-use value included in each request, checked against a store of recently seen values and rejected if it reappears. Timestamps serve a similar purpose; requests outside an acceptable clock skew, typically a few minutes, are rejected outright, which also limits how long a captured nonce store needs to be retained.

For state-changing operations, idempotency keys serve a dual purpose: they protect against accidental duplicate submissions from retries while also ensuring that a replayed request produces no additional effect, since the server recognises the key and returns the original result rather than repeating the action.

Signing requests, not just authenticating the caller, closes the loop: a signature computed over the request body, timestamp and nonce means a captured request cannot be altered or resubmitted at a later time without failing validation. Combined, short-lived tokens, nonce tracking, timestamp windows and idempotency keys give replay attacks very little room to succeed.

Five safeguards that prevent API request replay

Security considerations for API versioning and backward compatibility

Versioning is a security concern as much as a compatibility one, because an old version left running indefinitely is effectively an unpatched endpoint that nobody is actively defending. Every version in production should appear in the API inventory with an owner and a retirement date, not just a changelog entry.

Backward-incompatible changes to authentication or authorisation logic are the riskiest category: loosening a validation rule to preserve compatibility with an older client is how security regressions quietly slip into a new release. The safer pattern is additive change wherever possible, introducing new fields and endpoints rather than altering the meaning of existing ones, and deprecating old versions on a published timeline rather than leaving them live by default.

Each version should be treated as a distinct surface for authorisation testing. A BOLA fix applied to version 2 of an endpoint does nothing for version 1 if both remain reachable, so regression tests need to run against every supported version, not just the latest. Clear sunset dates, communicated well ahead of enforcement and backed by usage telemetry showing which clients still call the old version, make retirement a planned event rather than a breaking surprise. Contract tests in CI should fail the build when a new version silently removes a validation rule present in the one it replaces.

Security considerations for API versioning and backward compatibility — overview diagram

How we think about prioritisation when securing APIs

Our engineering-first delivery model means the architects reviewing an API’s authorisation logic are the same people who write the fix, which shortens the loop between finding a BOLA gap and closing it. A typical engagement starts with the controls that stop the most common exploitation paths, authentication, TLS, schema validation, before extending to payload inspection or mTLS where the risk profile justifies the added latency.

That sequencing reflects a real trade-off: advanced runtime protections cost performance and engineering time, so we reserve them for the endpoints where the data or business logic actually warrants it, rather than applying uniform heavy inspection everywhere.

— Pepe F.

Strengthen your APIs with an architecture review

Securing an API properly touches authentication, schema design, gateway configuration and telemetry all at once, which is exactly the kind of cross-cutting work that benefits from a second set of experienced eyes before it reaches production. Our custom software development and architecture review services cover secure API design, code audits for existing systems, and the technical debt review needed before a legacy API can be safely modernised.

Vicedomini Softworks

For teams that need ongoing security leadership without a full-time hire, our CTO Advisory service starts from €1,800 per month and gives direct access to the engineers reviewing your architecture, not an account manager relaying it secondhand. Readers publishing content or documentation through their own APIs may also find this partner guide to API content publishing useful for keeping canonical and structured data intact. Get in touch to scope an architecture review for your API estate.

FAQ

What are the best practices for API security?

The core set covers TLS everywhere, strong authentication paired with service-local authorisation checks, short-lived tokens with signature validation, schema-driven input and response validation, and rate limiting enforced at the gateway. NIST SP 800-228 frames these as combined pre-runtime and runtime protections rather than a single control.

What are the best practices for API design?

Secure API design starts with a schema-first contract, written in OpenAPI or a comparable interface definition language, validated at the boundary so unexpected fields and malformed payloads never reach business logic. Versioning should be additive wherever possible, with old versions tracked in an inventory and retired on a published timeline.

How does rate limiting protect an API from abuse?

Rate limiting caps how many requests a user, client or IP address can make within a given window, which prevents both denial-of-service attempts and runaway costs from misbehaving integrations. OWASP’s guidance on unrestricted resource consumption recommends pairing rate limits with payload size caps and limits on batch operations for complete coverage.

Sources

This article was produced with AI assistance and reviewed for accuracy. It is provided for general information only and is not professional advice.