API Security Architecture: Building Blocks, Patterns and Tests

API security architecture is the placement of controls across clients, gateways and services: which component verifies identity, which decides permissions, where transport is protected, where messages are validated, where resource use is limited, how secrets are handled, and what gets logged. A secure architecture gives every control an owner and a test, not just a box on a diagram.
If you want every block below tested automatically, Qodex runs the API security checks on every pull request without you writing them.
| Block | What it stops | OWASP 2023 | How to prove it |
|---|---|---|---|
| API gateway (edge) | Unauthenticated, malformed, oversized and flooding requests reaching services | API2, API4, API8, API9 | No token, wrong audience, unknown route, bad body, oversized body, burst: the documented 400, 401, 403, 404, 413 or 429, and no backend call |
| Authentication and token service | Forged, expired, replayed or misdirected credentials | API2 | Mutate issuer, audience, signature, expiry, redirect URI, PKCE; each is rejected at the right endpoint |
| Authorization in the service | One user reading or changing another user's objects, fields or functions | API1, API3, API5, API6 | Two accounts; swap object IDs, roles, methods, hidden fields and workflow order; the server denies, not the UI |
| Service mesh and mTLS | Unverified or impersonated workloads talking to each other | API2, API8 | No certificate, expired, untrusted, wrong workload: the handshake or policy fails before business logic |
| Rate and resource controls | One caller exhausting CPU, memory, storage or downstream budget | API4, API6 | Below, at and above each limit; backend work stays bounded; no test assumes an exact ceiling |
| Schema validation | Structurally invalid or over-privileged input reaching code | API3, API8 | Missing, extra, wrong-type and oversized fields, wrong content type: rejected before the backend |
| Secrets, keys and certificates | Leaked or stale credentials that keep working | API8 | A canary secret is caught by scanners; after rotation the old value fails |
| Logging, monitoring and inventory | Undetected abuse, untraceable decisions, forgotten endpoints | API8, API9 | One request ID across hops, decision visible, no raw token, a retired route raises an alert |
This guide takes those rows in order and names the standard behind each. The parent guide is API security testing.
What is API security architecture?
Architecture is placement. A best-practices list says validate tokens. An architecture names the component that validates them, the one that decides whether this caller may touch this record, and the one that proves the caller is the workload it claims.
One request crosses the edge. From there it may reach a service directly, cross the mesh to an internal service, or leave through the egress point. The tag beside each component is the test that proves it.
Three boundaries matter. North-south separates outside clients from your application, enforced at the gateway. East-west separates your own workloads, enforced by mesh proxies carrying workload identity. Egress is the third: a secure inbound path says nothing about an outbound dependency.
NIST SP 800-207 grants no implicit trust from network location: a policy decision point evaluates each request, a policy enforcement point applies the answer. The decision is made per session, from identity, device, resource and environment signals, and it grants least privilege, so the same caller can be allowed one minute and refused the next. Nor does the gateway finish the job. NIST SP 800-204 leaves fine-grained authorization to the microservice, the only entity with full knowledge of the business logic.
Keep authentication and authorization apart, the split most guides blur. Authentication establishes who made the request; OpenID Connect Core adds that layer to OAuth 2.0 and returns an ID Token describing the login event. Authorization decides whether that identity may act on this object. OAuth 2.0 grants limited access, per RFC 6749, but never says who owns a given invoice.
The blocks travel with the API. Design places them. Build validates schemas and keeps secrets out of code. Deploy issues certificates and sets limits. Production watches decisions and abuse. Retirement drops the route from gateway and inventory, then checks it is gone.
API gateway: the north-south policy point
The gateway carries TLS policy, the route allowlist, token verification, coarse scope checks, size limits, schema checks, throttles, request IDs and access logs. Object ownership and business authorization stay in the service.
Three product documents show the same shape; none is a recommendation. AWS documents access management, data protection, logging, request validation and throttling as separate API Gateway controls. Its request validator fails a bad request with a 400 before the integration request, which it says reduces calls to the backend. Apigee groups API keys, OAuth, SAML, data masking, content-based security, key-value storage, quota enforcement and TLS controls around the API proxy, which makes the proxy the policy point. Kong documents Basic, OAuth 2.0, OpenID Connect, SAML, API-key and LDAP authentication at the gateway, so a request reaches no upstream service until the client has authenticated, and it protects its own administration plane with role-based access control.
Hold your gateway to the rule those three share: a rejection at the edge means no backend call. Run the gateway row from the table above, expect the code your contract documents, and assert the missing backend call from backend logs or a mock upstream.
Authentication and authorization: identity is not permission
Authentication: OAuth 2.0, OpenID Connect and token validation
OAuth 2.0 lets a client obtain limited access to an HTTP service. RFC 6749 defines the framework; build against RFC 9700, which is stricter where implementations break.
RFC 9700 requires the authorization server to match a redirect URI against the registered one by exact string comparison, excepting variable port numbers in localhost URIs for native apps. It requires PKCE for public clients and authorization servers, recommends it for confidential clients, and forbids open redirectors. Flows returning access tokens in the authorization response are exposed to leakage and replay, because the token travels back through the browser. RFC 8252 requires native apps to use an external user agent, normally the system browser, plus PKCE, and does not recommend the implicit flow for them.
OpenID Connect Core uses the openid scope and returns an ID Token, a JWT carrying claims about the authentication event. The access token calls the resource server; the ID Token tells the client who signed in. A service that accepts an ID Token as an access token has a broken boundary. See API authentication methods and how OAuth 2.0 works.
Validation is where the architecture becomes code. RFC 7519 says that when aud is present it must identify the receiving service, exp must be in the future and nbf must have passed. RFC 8725 adds the deployment rules: libraries must let the caller name a supported set of algorithms and use no others, issuer and audience are checked, and no claim is trusted before validation. See JSON Web Tokens.
Mutate one thing at a time and confirm the owning endpoint rejects it: issuer, audience, algorithm, signature, expiry, not-before, redirect URI, state, nonce, PKCE verifier, scope.
Authorization: object, property, function and workflow decisions
Authorization decisions live next to the data and the business rule. NIST SP 800-204B models them as attribute-based access control: a decision computed from subject, object, requested action, environment and policy attributes, applied to end-user and service identities alike.
The gateway can enforce which routes exist and which scopes reach them. It cannot know that user A owns invoice B, having no view of the ownership table. That gap covers four 2023 OWASP risks: API1, API3, API5 and API6.
Test with two accounts, in two tenants, with different roles. Replay one request while changing one thing: object ID, tenant ID, method, a hidden property, the order of steps. The server must deny it, not merely the UI.
mTLS and service-to-service security
Mutual TLS means both sides authenticate during the handshake, before any application logic runs.
RFC 8705 defines two controls people conflate. Mutual-TLS client authentication proves the client to the authorization or resource server. Certificate-bound access tokens tie a token to the client's certificate, making a stolen bearer token useless without the private key. Use them together or separately.
NIST SP 800-204A describes the mesh shape: one proxy beside each service instance, separating traffic controls from application code. Its control set covers certificate and key management, authentication, authorization, mTLS, rate limiting, logging and tracing. It also says service proxies should communicate only over mutual TLS sessions, each holding a distinct identity in its certificate. Istio documents the same pieces: a certificate authority, sidecar and perimeter proxies, request authentication, authorization policy, telemetry and audit support. The audit trail is what turns a mesh decision into evidence someone can read later.
Transport authentication proves which workload is calling. It is not application authorization: a correctly authenticated payments service can still ask for a record it should not see.
Test with no client certificate, an expired one, an untrusted one, and one for the wrong workload; each fails before business logic. Then rotate: the new credential works, the old stops.
Rate limits and resource controls
A rate limit is one control, not the denial-of-service plan. The real list is longer: request rate, burst, concurrency, payload size, pagination and query depth, batching, timeouts, and a budget for the downstream calls one request triggers.
NIST SP 800-204 lists throttling alongside load balancing and resiliency among the core features a gateway or mesh can package. AWS implements API Gateway throttling with a token bucket and may return 429 when a caller exceeds the rate, but calls those limits best-effort targets, not guaranteed ceilings. Assert that the limit engages, and never assert the exact request number that trips it.
Query shape matters as much as request count. One deep or batched query can cost more than a hundred cheap ones, and a per-route request limit cannot tell them apart. Depth, batching and timeout limits do that work, so they belong beside the rate limit.
This block owns API4 and shares API6 with the workflow rules. Test below, at and above every limit. Check the status code and the retry behaviour the contract promises, then confirm downstream calls stayed bounded.
Schema validation at the edge, business validation in the service
Edge validation rejects structure. The AWS API Gateway request validator checks required parameters and validates the body against a JSON Schema model; when validation fails it returns a 400 and does not call the integration. That last part is the property worth testing: not the 400, but the missing backend call.
Service validation rejects meaning. A JSON Schema already handles part of this: a minimum stops a negative quantity, a maximum stops a discount above the cap, and a rule against extra fields stops an isAdmin field on a self-service form. What a schema cannot judge is the rule that depends on context. A discount this customer's plan does not allow, a status transition that skips a step, an order for stock already reserved: valid JSON, all wrong. Those rules live in the business logic, so the service has to refuse them.
The pair maps to API3 and API8. Remove required fields, add unknown fields, change types, send the wrong content type. Then send valid JSON in an invalid business state and watch the service, not the gateway, refuse it. API fuzz testing automates the first half.
Secrets, keys, certificates and rotation
API keys, OAuth client secrets, signing keys and mTLS private keys are architecture. Keep them out of code and logs, give each workload only what it needs, and treat expiry and rotation as deployment steps with owners.
NIST SP 800-204A puts certificate generation and key management inside the service-mesh control set, next to the proxies that use them. RFC 8725 supplies the JWT half: permitted algorithms, validated cryptographic operations, and validated issuer and audience, so a key that should no longer be trusted actually stops working.
Two tests prove the block. Seed a harmless canary secret and confirm your repository, build-log, image and runtime-log scanners catch it. Then rotate every credential in a test environment: the new value works, the old is rejected. No interval belongs here, because rotation frequency depends on exposure and compliance obligations.
Logging, monitoring and API inventory
Every security event should carry a request ID that survives each hop, the identity behind the request, the policy decision behind the response code, the latency, and the downstream path the request took. The architecture question is which component writes which field. The gateway knows the route and the token it validated. The service knows the object and the decision. The mesh proxy knows the calling workload. Redact tokens and secrets where the line is written, not further along. API security monitoring covers the full event schema and what to alert on.
NIST SP 800-204 and 800-204A list logging, metrics and distributed tracing among the packaged features, and NIST SP 800-207 makes the per-session decision something a zero-trust architecture records. AWS documents logging and monitoring for API Gateway as a control in its own right. These fields are your evidence.
Inventory is the other half, and it is where API9 lives. Compare your list of exposed routes and versions with what is deployed, on a schedule rather than after an incident. Old versions, forgotten environments and undocumented methods count. The wider program is API security posture management, and the API security checklist is the operational follow-up.
Trace one allowed and one denied request across gateway and service logs by request ID. Assert the decision is visible and the raw token is not. Then hit a retired route and confirm it is denied and something alerts.
Four API security reference patterns
Most systems land in one of four shapes. The table says what each fits and what each cannot protect.
| Pattern | Fits | What it cannot protect |
|---|---|---|
| Edge gateway only | A monolith or a few externally reached services | Workload-to-workload calls it never sees, and object ownership |
| Backend for frontend, or a microgateway per client | Several client types needing different edge policy | Nothing by itself, but each copy of the policy drifts without a shared policy service |
| Gateway plus service mesh | Many workloads calling each other, needing identity and mTLS | Object-level business authorization. The mesh can decide which workload may call which service, but not whether this end user owns this record |
| Controlled egress to third parties | Any system that calls partner APIs | A compromised dependency whose responses are well formed, and misuse the outbound policy reads as normal traffic; without a policy point, validation and timeouts, API7 and API10 land here |
A gateway is enough while every call worth protecting crosses the edge. A mesh earns its place once your workloads call each other and those calls need workload identity, mTLS and policy the gateway cannot see, not being on that path. That split is NIST SP 800-204 and 800-204A: a deployment shape, not a product choice.
NIST SP 800-204 lists load balancing and resiliency next to throttling, so availability controls sit at the same boundary as the security ones.
Map the OWASP API Security Top 10 to architecture blocks
The risk names below are the OWASP API Security Top 10 (2023). The mapping and tests are this page's analysis, not OWASP's. For the risk-by-risk detail, read the OWASP API Security Top 10 guide.
| OWASP category | Primary block | Test that proves the control |
|---|---|---|
| API1: Broken Object Level Authorization | Application authorization | User A's token, user B's object: denied on read, update and delete |
| API2: Broken Authentication | Identity provider and gateway validator | Expired, unsigned, wrong-issuer and revoked tokens; abuse reset and refresh |
| API3: Broken Object Property Level Authorization | Schema validator and application authorization | Add privileged input fields, request hidden response fields |
| API4: Unrestricted Resource Consumption | Gateway throttles and service budgets | Cross the request, concurrency, payload, query-depth and cost limits |
| API5: Broken Function Level Authorization | Gateway route policy and function authorization | Low-privilege token against admin routes, old versions, guessed paths |
| API6: Unrestricted Access to Sensitive Business Flows | Workflow rules and abuse controls | Automate the sequence, skip steps, replay actions, exceed booking caps |
| API7: Server Side Request Forgery | Egress policy point | Loopback, link-local, private-network and redirect-chain targets are blocked |
| API8: Security Misconfiguration | Every block, especially policy as code | Default routes, debug endpoints, verbose errors, weak TLS, stale certificates |
| API9: Improper Inventory Management | Gateway catalog and OpenAPI inventory | Deployed routes against the approved specification; old versions, shadow hosts |
| API10: Unsafe Consumption of APIs | Egress gateway and response validator | Malformed, oversized, slow and redirected upstream responses meet validation |
Read the mapping as a primary owner, not a fence. This is analysis, not OWASP text, and several risks cross blocks: API8 touches all of them.
Turn the architecture into tests that run on every pull request
Take a pull request that changes an OpenAPI schema, adds an OAuth scope and moves a service route. Three boxes on the diagram just changed, and a diff review answers the question of whether the boundary still holds from memory.
The alternative is to turn each box into a saved negative test: wrong audience at the gateway, cross-tenant object read in the service, wrong workload certificate in the mesh, a canary secret in a log line, a missing audit event. Each records the identity, the request, the test data it used, the expected decision, the actual response and the policy revision, and replays on every later pull request, so a result changes only when the system does.
NIST SP 800-204C describes the machine around them: cloud-native DevSecOps built from application code, application-services code, infrastructure as code, policy as code and observability as code, moving through build, test, package, deploy and operations stages. Negative security tests belong in the test stage, versioned with the policy they check.
Run it only against an API and test accounts you own or are authorized to test.
#!/usr/bin/env bash
# Four architecture boundaries, checked against a running API.
set -u
: "${BASE_URL:?set BASE_URL}"
: "${TOKEN_A:?set TOKEN_A}"
: "${TOKEN_B:?set TOKEN_B for the invoice owner}"
: "${INVOICE_B:?set INVOICE_B to an invoice owned by another account}"
DENY_STATUS="${DENY_STATUS:-403}"
fail=0
check() {
name="$1"
expected="$2"
shift 2
actual=$(curl -sS -o /dev/null -w '%{http_code}' "$@")
if [ "$actual" = "$expected" ]; then
printf 'PASS %s (%s)\n' "$name" "$actual"
else
printf 'FAIL %s expected %s, got %s\n' "$name" "$expected" "$actual"
fail=1
fi
}
check 'owner baseline' 200 \
-H "Authorization: Bearer ${TOKEN_B}" \
"${BASE_URL}/v1/invoices/${INVOICE_B}"
check 'authentication' 401 \
"${BASE_URL}/v1/invoices/${INVOICE_B}"
check 'object authorization' "$DENY_STATUS" \
-H "Authorization: Bearer ${TOKEN_A}" \
"${BASE_URL}/v1/invoices/${INVOICE_B}"
check 'schema allowlist' 400 \
-X POST -H "Authorization: Bearer ${TOKEN_A}" \
-H 'Content-Type: application/json' \
--data '{"amount":100,"isAdmin":true}' \
"${BASE_URL}/v1/invoices"
for attempt in $(seq 1 "${BURST_REQUESTS:-25}"); do
code=$(curl -sS -o /dev/null -w '%{http_code}' \
-H "Authorization: Bearer ${TOKEN_A}" \
"${BASE_URL}/v1/invoices")
[ "$code" = 429 ] && { printf 'PASS rate limit (429)\n'; exit "$fail"; }
done
printf 'FAIL rate limit did not return 429\n'
exit 1
Replace the paths, accounts and expected codes with what your API documents. Some APIs answer 404 rather than 403 for an object the caller may not see, and DENY_STATUS exists for that. The burst count is not universal either, because throttles are best-effort targets.
Qodex runs part of that plan for you. It starts from authenticated flows it has already tested, then executes attack chains against your preview deployment on every pull request, using two real accounts in two organizations you control, typically an owner and a member, so cross-tenant reads and privilege escalation are attempted rather than assumed. A finding is a chain that reached its impact, reported with the request, the response and the step that let it through. semgrep, gitleaks and osv-scanner set the floor. Against the eight blocks on this page, that is the authentication and authorization rows plus the secrets-in-code half of the secrets row. It is not a penetration test, and the mTLS handshake, schema rejections, throttles, rotation, log redaction and egress checks stay in the contract tests you own.
Frequently Asked Questions
What does API security architecture mean?
It is the placement of security controls across clients, gateways, services and downstream systems: which component verifies identity, which decides permissions, where transport is protected, where messages are validated, where resource use is capped, and what gets recorded. It spans north-south at the gateway, east-west between workloads, and egress to third parties.
What are the main components of API security architecture?
Eight blocks: the API gateway at the edge, the authentication and token service, authorization inside the business service, the service mesh with mutual TLS, rate and resource controls, schema validation, secrets and certificate management, and logging with an API inventory. Each has one owner, one boundary, and a test that fails when the control goes missing.
What is the difference between an API gateway and a service mesh?
A gateway sits on the north-south path and applies policy to requests from outside: TLS, routes, token verification, coarse scopes, schemas and throttles. A mesh sits on the east-west path, giving each workload an identity and a proxy, so calls between your services are authenticated and encrypted. NIST SP 800-204 covers the gateway, 800-204A the mesh.
What is the difference between API authentication and authorization?
Authentication establishes who made the request. OpenID Connect adds that layer to OAuth 2.0 and returns an ID Token describing the login event. Authorization decides whether that identity may act on this object, and it runs in the service, where ownership lives. OAuth 2.0 grants access to a resource; it cannot say who owns a record.
Do internal APIs need mutual TLS?
It depends on the topology and the threat you are defending against. NIST SP 800-207 grants no implicit trust from network location, so being inside the perimeter is not a credential. Where a service mesh carries the traffic, NIST SP 800-204A recommends that service proxies communicate only over mutual TLS sessions, each holding a distinct identity. Mutual TLS proves which workload calls; it does not decide what it may do.
Where should rate limiting and schema validation happen?
Structural checks and edge rate controls belong at the gateway, before the backend runs, and the service keeps its own resource and downstream-call budgets. AWS API Gateway returns a 400 when request validation fails and does not call the integration, and may return 429 when a caller exceeds its throttles, which it calls best-effort targets. Business validation belongs in the service, which alone knows a valid-looking order is impossible.
How do you test API security architecture in a CI pipeline?
Give each block one saved negative test and run them all on every pull request. Record the identity used, the request, the test data, the expected decision, the actual response and the policy revision, so a result changes only when the system changes. Use two accounts in two tenants for the authorization cases.
Draw the boundaries, then prove them: run API security checks on pull requests so a control that stops working shows up in the diff that broke it.





