# API Design and Contract Security

> **Intro:** API security starts before runtime. Contract design determines what can be validated, what can be logged, what clients will assume, and how authorization mistakes get hidden or prevented.

## Focus areas

* OpenAPI quality and review
* transport, auth, and error semantics
* data model exposure
* versioning and deprecation
* contract linting in CI
* authorization-aware contract review

## Core idea

A useful API contract is not just documentation. It is a **security control surface**.

If the contract is weak or ambiguous, teams often try to “bolt security on later” with gateway policy, WAF rules, or ad hoc handler logic. That usually creates drift between the documented API and the real API.

## What older material got right

Older Swagger/OpenAPI-oriented guidance was correct about one important thing: **the API definition itself is the starting point for API security**.

The parts that need modernization are mostly around:

* newer OpenAPI versions and validation workflows;
* stronger treatment of authorization and object ownership;
* treating the spec as a merge-gated artifact, not a documentation afterthought.

## Old versus current framing

| Older pattern                 | Why it was common               | Better current framing                                            |
| ----------------------------- | ------------------------------- | ----------------------------------------------------------------- |
| Swagger spec for docs only    | product teams wanted docs first | OpenAPI as a reviewable security artifact                         |
| auth only in gateway config   | team ownership was split        | auth semantics in spec plus gateway enforcement                   |
| schema review only for syntax | easiest way to start            | semantics + auth + data exposure + error behavior review          |
| one-off API security review   | APIs changed more slowly        | spec linting and targeted authz checks on every meaningful change |

## Security domains to review in every contract

### 1. Transport

Define whether the API is intended only behind HTTPS and whether plaintext exposure is ever acceptable. In practice, the answer for public and sensitive internal APIs should be **no**.

### 2. Authentication

Make the scheme explicit:

* OAuth 2.0 bearer token;
* mTLS;
* signed webhook secret;
* internal workload identity;
* session cookie if the API is browser-facing.

Avoid undocumented fallback auth behavior.

### 3. Authorization

This is where many APIs fail. Review:

* object ownership;
* tenant scoping;
* admin-only routes;
* support impersonation paths;
* bulk operations;
* export or report generation routes.

The contract should make it obvious which endpoints are privileged and what scope or role is expected.

### 4. Data validation

Define:

* required fields;
* enum boundaries;
* maximum lengths;
* numeric limits;
* array size limits;
* whether unknown fields are rejected.

### 5. Error behavior

Do not leak internals through error bodies. Prefer stable error codes and messages that help clients debug safely without exposing stack details or authorization logic.

## Add business invariants to contract review

A contract can be syntactically correct and still support insecure business behavior. During review, capture:

* forbidden state transitions;
* object and workflow ownership assumptions;
* negative or duplicate operations that must be rejected;
* which values deserve stronger domain types instead of free-form strings.

This keeps API design aligned with secure-by-design thinking instead of treating the spec as syntax alone.

## Practical review checklist

Ask these questions during contract review:

* Is every operation tagged with the expected auth mechanism?
* Are privileged routes easy to spot?
* Are user-owned and tenant-owned objects clearly identified?
* Are list, search, and export endpoints bounded?
* Are file upload/download routes explicit about content type and validation?
* Are deprecated endpoints still protected and monitored?
* Can a reviewer tell what should be logged for sensitive operations?

## Practical snippet — OpenAPI security scheme

```yaml
openapi: 3.1.0
info:
  title: Invoice API
  version: 1.2.0

components:
  securitySchemes:
    bearerAuth:
      type: http
      scheme: bearer
      bearerFormat: JWT

security:
  - bearerAuth: []

paths:
  /v1/invoices/{invoiceId}:
    get:
      summary: Get one invoice
      operationId: getInvoice
      parameters:
        - in: path
          name: invoiceId
          required: true
          schema:
            type: string
            pattern: '^[a-f0-9-]{36}$'
      responses:
        '200':
          description: Invoice found
        '403':
          description: Caller is authenticated but not allowed to access this invoice
        '404':
          description: Invoice not found
```

## Practical snippet — Redocly rules config

```yaml
apis:
  main:
    root: ./openapi.yaml

rules:
  operation-operationId: error
  security-defined: error
  no-http-verbs-in-paths: warn
  no-unused-components: warn
  path-parameters-defined: error
  spec: error
```

Run it with:

```bash
npx @redocly/cli lint openapi.yaml
```

## Practical snippet — authz-focused contract test example

```python
import requests

def test_invoice_cannot_cross_tenant(api_base, tenant_a_token, tenant_b_invoice_id):
    r = requests.get(
        f"{api_base}/v1/invoices/{tenant_b_invoice_id}",
        headers={"Authorization": f"Bearer {tenant_a_token}"},
        timeout=10,
    )
    assert r.status_code in (403, 404)
```

This is the kind of simple targeted test that catches real authorization failures better than a pretty contract document alone.

## Legacy versus current format note

### Older but still common

```yaml
swagger: '2.0'
```

### Current preference

```yaml
openapi: 3.1.0
```

Older Swagger 2.0 documents still exist and are still readable, but for new design work prefer a maintained OpenAPI workflow and lint rules that can express modern schema behavior more clearly.

## Common mistakes

* documenting auth in prose but not in the spec;
* defining authentication and forgetting authorization;
* allowing unbounded search, export, or batch operations;
* treating `nullable`, enums, and additional fields loosely until runtime;
* assuming the gateway will correct a weak contract.

## Related hands-on lab

* [API Definition Conformance Lab — OpenAPI, Contract Linting, AuthZ Checks, and CI Validation](/learning-labs-interview-and-templates/index-2/api-definition-conformance-lab-openapi.md)

## Related pages

* [API Authentication and Authorization](/architecture-api-crypto-and-identity/index/api-authentication-and-authorization.md)
* [API Testing, Observability, and Release Gates](/architecture-api-crypto-and-identity/index/api-testing-observability-and-release-gates.md)
* [Develop Phase — Practical DevSecOps Controls](/devsecops-cicd-and-supply-chain/index/develop.md)

\---*Author attribution: Ivan Piskunov, 2026 - Educational and defensive-engineering use.*


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://docs.product-security.expert/architecture-api-crypto-and-identity/index/api-design-and-contract-security.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
