{
  "generated_at": "2026-07-28T05:29:41.234Z",
  "format": "zrz.io/zbp",
  "spec_url": "https://zrz.io/zbp/0-blueprints",
  "bundles": [
    {
      "id": "multi-tenant-saas",
      "title": "Multi-tenant SaaS: identity and isolation",
      "description": "Everything needed to stand up authentication and tenant isolation for a B2B SaaS product: the isolation boundary, the identity and membership model on top of it, and sender-constrained credentials for its machine callers.",
      "roots": [
        "ZBP-4"
      ],
      "includes": [
        {
          "ref": "ZBP-1",
          "title": "DPoP-bound requests across an API surface",
          "version": "1.0.0"
        },
        {
          "ref": "ZBP-3",
          "title": "Tenant isolation in a multi-tenant system",
          "version": "1.0.0"
        },
        {
          "ref": "ZBP-4",
          "title": "Authentication for a multi-tenant SaaS product",
          "version": "1.0.0"
        }
      ],
      "raw_url": "https://zrz.io/zbp/bundle/multi-tenant-saas.md"
    },
    {
      "id": "workload-identity",
      "title": "Workload identity: an STS and the credentials it issues",
      "description": "Service-to-service authentication with no long-lived secrets: a token service bootstrapped from platform attestation, issuing short-lived tokens bound to a holder key.",
      "roots": [
        "ZBP-2"
      ],
      "includes": [
        {
          "ref": "ZBP-1",
          "title": "DPoP-bound requests across an API surface",
          "version": "1.0.0"
        },
        {
          "ref": "ZBP-2",
          "title": "A Security Token Service for workload identity",
          "version": "1.0.0"
        }
      ],
      "raw_url": "https://zrz.io/zbp/bundle/workload-identity.md"
    }
  ],
  "blueprints": [
    {
      "id": 0,
      "ref": "ZBP-0",
      "title": "Blueprints",
      "version": "1.0.0",
      "major": 1,
      "status": "stable",
      "date": "2026-07-27",
      "updated": null,
      "authors": [
        "Theo Zourzouvillys"
      ],
      "tags": [
        "meta",
        "process",
        "llm",
        "standards"
      ],
      "summary": "What Blueprints are: versioned, normative implementation specifications for cross-cutting concerns, written to be pulled into a build by URL and implemented directly — by a person or by a language model — with numbered requirements you can grep for.",
      "use_when": "You are writing a Blueprint, or you want to understand the contract a Blueprint offers before pulling one into a build.",
      "not_for": [
        "Deciding whether a practice is a good idea — that argument lives in a Field Note, not here.",
        "Learning a technology from scratch; a blueprint assumes you know the domain and want the specification."
      ],
      "requires": [],
      "provides": [
        "blueprint-format"
      ],
      "implements_notes": [
        {
          "id": 0,
          "ref": "ZFN-0",
          "url": "https://zrz.io/zfn/0"
        },
        {
          "id": 14,
          "ref": "ZFN-14",
          "url": "https://zrz.io/zfn/14"
        },
        {
          "id": 30,
          "ref": "ZFN-30",
          "url": "https://zrz.io/zfn/30"
        },
        {
          "id": 45,
          "ref": "ZFN-45",
          "url": "https://zrz.io/zfn/45"
        },
        {
          "id": 47,
          "ref": "ZFN-47",
          "url": "https://zrz.io/zfn/47"
        }
      ],
      "supersedes": null,
      "superseded_by": null,
      "aliases": [],
      "requirements": {
        "count": 14,
        "ids": [
          "ZBP-0-R1",
          "ZBP-0-R2",
          "ZBP-0-R3",
          "ZBP-0-R4",
          "ZBP-0-R5",
          "ZBP-0-R6",
          "ZBP-0-R7",
          "ZBP-0-R8",
          "ZBP-0-R9",
          "ZBP-0-R10",
          "ZBP-0-R11",
          "ZBP-0-R12",
          "ZBP-0-R13",
          "ZBP-0-R14"
        ]
      },
      "content_sha256": "e6635a20f8a778bac1b413d391406399e9b8c4f55c575ce3c9c91f5360948bda",
      "source": "src/content/blueprints/0-blueprints.md",
      "url": "https://zrz.io/zbp/0-blueprints",
      "raw_url": "https://zrz.io/zbp/0-blueprints.md",
      "pinned_raw_url": "https://zrz.io/zbp/0-blueprints/v1.md"
    },
    {
      "id": 1,
      "ref": "ZBP-1",
      "title": "DPoP-bound requests across an API surface",
      "version": "1.0.0",
      "major": 1,
      "status": "stable",
      "date": "2026-07-27",
      "updated": null,
      "authors": [
        "Theo Zourzouvillys"
      ],
      "tags": [
        "security",
        "auth",
        "http",
        "tokens",
        "dpop"
      ],
      "summary": "A complete specification for sender-constrained HTTP requests using DPoP (RFC 9449): key handling, proof construction, token binding via cnf.jkt, the resource-server validation algorithm in order, nonces, replay defence, and executable test vectors.",
      "use_when": "You are issuing or accepting access tokens over HTTP and want a stolen token to be useless without the holder's private key.",
      "not_for": [
        "Service-to-service calls where mutual TLS is already terminated end-to-end — mTLS-bound tokens (RFC 8705) are a better fit.",
        "Protecting the request body's integrity end-to-end; DPoP binds the request line, not the payload.",
        "Authorising *what* a principal may do; this is proof-of-possession, not authorisation."
      ],
      "requires": [],
      "provides": [
        "dpop-bound-requests",
        "sender-constrained-tokens"
      ],
      "implements_notes": [
        {
          "id": 6,
          "ref": "ZFN-6",
          "url": "https://zrz.io/zfn/6"
        },
        {
          "id": 7,
          "ref": "ZFN-7",
          "url": "https://zrz.io/zfn/7"
        },
        {
          "id": 30,
          "ref": "ZFN-30",
          "url": "https://zrz.io/zfn/30"
        },
        {
          "id": 45,
          "ref": "ZFN-45",
          "url": "https://zrz.io/zfn/45"
        }
      ],
      "supersedes": null,
      "superseded_by": null,
      "aliases": [],
      "requirements": {
        "count": 27,
        "ids": [
          "ZBP-1-R1",
          "ZBP-1-R2",
          "ZBP-1-R3",
          "ZBP-1-R4",
          "ZBP-1-R5",
          "ZBP-1-R6",
          "ZBP-1-R7",
          "ZBP-1-R8",
          "ZBP-1-R9",
          "ZBP-1-R10",
          "ZBP-1-R11",
          "ZBP-1-R12",
          "ZBP-1-R13",
          "ZBP-1-R14",
          "ZBP-1-R15",
          "ZBP-1-R16",
          "ZBP-1-R17",
          "ZBP-1-R18",
          "ZBP-1-R19",
          "ZBP-1-R20",
          "ZBP-1-R21",
          "ZBP-1-R22",
          "ZBP-1-R23",
          "ZBP-1-R24",
          "ZBP-1-R25",
          "ZBP-1-R26",
          "ZBP-1-R27"
        ]
      },
      "content_sha256": "73ed5cad587b4f2c7fef5e1fed341f72f7cf730f7e010ad50a31ad6af0a71388",
      "source": "src/content/blueprints/1-dpop-bound-requests.md",
      "url": "https://zrz.io/zbp/1-dpop-bound-requests",
      "raw_url": "https://zrz.io/zbp/1-dpop-bound-requests.md",
      "pinned_raw_url": "https://zrz.io/zbp/1-dpop-bound-requests/v1.md"
    },
    {
      "id": 2,
      "ref": "ZBP-2",
      "title": "A Security Token Service for workload identity",
      "version": "1.0.0",
      "major": 1,
      "status": "stable",
      "date": "2026-07-27",
      "updated": null,
      "authors": [
        "Theo Zourzouvillys"
      ],
      "tags": [
        "security",
        "auth",
        "identity",
        "tokens",
        "infra",
        "sts"
      ],
      "summary": "A complete specification for a workload STS: platform attestation as the only bootstrap, RFC 8693 token exchange, downscope-only policy, short-lived at+jwt tokens bound to a holder key, KMS signing keys with overlapping rotation, and local verification.",
      "use_when": "Services in your platform need to authenticate to each other and you want every call attributable to a named workload holding no long-lived secret.",
      "not_for": [
        "End-user authentication, sessions, or consent — this issues machine credentials, not user logins.",
        "Authorisation policy itself; the STS decides what a workload may be *issued*, not what it may *do* once inside a service.",
        "A platform with one runtime and one service, where the token exchange costs more than it returns."
      ],
      "requires": [
        {
          "id": 1,
          "ref": "ZBP-1",
          "title": "DPoP-bound requests across an API surface",
          "url": "https://zrz.io/zbp/1-dpop-bound-requests"
        }
      ],
      "provides": [
        "workload-identity",
        "token-exchange",
        "short-lived-service-credentials"
      ],
      "implements_notes": [
        {
          "id": 4,
          "ref": "ZFN-4",
          "url": "https://zrz.io/zfn/4"
        },
        {
          "id": 5,
          "ref": "ZFN-5",
          "url": "https://zrz.io/zfn/5"
        },
        {
          "id": 9,
          "ref": "ZFN-9",
          "url": "https://zrz.io/zfn/9"
        },
        {
          "id": 16,
          "ref": "ZFN-16",
          "url": "https://zrz.io/zfn/16"
        },
        {
          "id": 38,
          "ref": "ZFN-38",
          "url": "https://zrz.io/zfn/38"
        },
        {
          "id": 40,
          "ref": "ZFN-40",
          "url": "https://zrz.io/zfn/40"
        },
        {
          "id": 49,
          "ref": "ZFN-49",
          "url": "https://zrz.io/zfn/49"
        }
      ],
      "supersedes": null,
      "superseded_by": null,
      "aliases": [],
      "requirements": {
        "count": 52,
        "ids": [
          "ZBP-2-R1",
          "ZBP-2-R2",
          "ZBP-2-R3",
          "ZBP-2-R4",
          "ZBP-2-R5",
          "ZBP-2-R6",
          "ZBP-2-R7",
          "ZBP-2-R8",
          "ZBP-2-R9",
          "ZBP-2-R10",
          "ZBP-2-R11",
          "ZBP-2-R12",
          "ZBP-2-R13",
          "ZBP-2-R14",
          "ZBP-2-R15",
          "ZBP-2-R16",
          "ZBP-2-R17",
          "ZBP-2-R18",
          "ZBP-2-R19",
          "ZBP-2-R20",
          "ZBP-2-R21",
          "ZBP-2-R22",
          "ZBP-2-R23",
          "ZBP-2-R24",
          "ZBP-2-R25",
          "ZBP-2-R26",
          "ZBP-2-R27",
          "ZBP-2-R28",
          "ZBP-2-R29",
          "ZBP-2-R30",
          "ZBP-2-R31",
          "ZBP-2-R32",
          "ZBP-2-R33",
          "ZBP-2-R34",
          "ZBP-2-R35",
          "ZBP-2-R36",
          "ZBP-2-R37",
          "ZBP-2-R38",
          "ZBP-2-R39",
          "ZBP-2-R40",
          "ZBP-2-R41",
          "ZBP-2-R42",
          "ZBP-2-R43",
          "ZBP-2-R44",
          "ZBP-2-R45",
          "ZBP-2-R46",
          "ZBP-2-R47",
          "ZBP-2-R48",
          "ZBP-2-R49",
          "ZBP-2-R50",
          "ZBP-2-R51",
          "ZBP-2-R52"
        ]
      },
      "content_sha256": "0b99e0d8cdf50ec9689155723cc1bb75b4e0b9e45c30903c10f9a3998a7a028d",
      "source": "src/content/blueprints/2-workload-security-token-service.md",
      "url": "https://zrz.io/zbp/2-workload-security-token-service",
      "raw_url": "https://zrz.io/zbp/2-workload-security-token-service.md",
      "pinned_raw_url": "https://zrz.io/zbp/2-workload-security-token-service/v1.md"
    },
    {
      "id": 3,
      "ref": "ZBP-3",
      "title": "Tenant isolation in a multi-tenant system",
      "version": "1.0.0",
      "major": 1,
      "status": "stable",
      "date": "2026-07-27",
      "updated": null,
      "authors": [
        "Theo Zourzouvillys"
      ],
      "tags": [
        "security",
        "saas",
        "multi-tenancy",
        "data",
        "database"
      ],
      "summary": "A complete specification for keeping tenants apart: tenant context established once from authenticated material, tenant id as partition key, enforcement in a layer application code cannot bypass, ownership verified at every boundary, and continuous leak detection.",
      "use_when": "One system stores or serves data belonging to more than one customer, and one customer seeing another's data would be a serious incident.",
      "not_for": [
        "Authorisation within a tenant — who may see what once you know the tenant is right is a separate problem.",
        "Single-tenant deployments, where the isolation boundary is the deployment itself.",
        "Deciding your pricing or packaging tiers; the isolation tier is an engineering choice, not a plan name."
      ],
      "requires": [],
      "provides": [
        "tenant-isolation",
        "tenant-context"
      ],
      "implements_notes": [
        {
          "id": 10,
          "ref": "ZFN-10",
          "url": "https://zrz.io/zfn/10"
        },
        {
          "id": 15,
          "ref": "ZFN-15",
          "url": "https://zrz.io/zfn/15"
        },
        {
          "id": 18,
          "ref": "ZFN-18",
          "url": "https://zrz.io/zfn/18"
        },
        {
          "id": 21,
          "ref": "ZFN-21",
          "url": "https://zrz.io/zfn/21"
        },
        {
          "id": 40,
          "ref": "ZFN-40",
          "url": "https://zrz.io/zfn/40"
        }
      ],
      "supersedes": null,
      "superseded_by": null,
      "aliases": [],
      "requirements": {
        "count": 38,
        "ids": [
          "ZBP-3-R1",
          "ZBP-3-R2",
          "ZBP-3-R3",
          "ZBP-3-R4",
          "ZBP-3-R5",
          "ZBP-3-R6",
          "ZBP-3-R7",
          "ZBP-3-R8",
          "ZBP-3-R9",
          "ZBP-3-R10",
          "ZBP-3-R11",
          "ZBP-3-R12",
          "ZBP-3-R13",
          "ZBP-3-R14",
          "ZBP-3-R15",
          "ZBP-3-R16",
          "ZBP-3-R17",
          "ZBP-3-R18",
          "ZBP-3-R19",
          "ZBP-3-R20",
          "ZBP-3-R21",
          "ZBP-3-R22",
          "ZBP-3-R23",
          "ZBP-3-R24",
          "ZBP-3-R25",
          "ZBP-3-R26",
          "ZBP-3-R27",
          "ZBP-3-R28",
          "ZBP-3-R29",
          "ZBP-3-R30",
          "ZBP-3-R31",
          "ZBP-3-R32",
          "ZBP-3-R33",
          "ZBP-3-R34",
          "ZBP-3-R35",
          "ZBP-3-R36",
          "ZBP-3-R37",
          "ZBP-3-R38"
        ]
      },
      "content_sha256": "1c947723d0a48749ff9a6bbc7d22a8744ddeece04a967c3e0e212d8d8bcb6573",
      "source": "src/content/blueprints/3-tenant-isolation.md",
      "url": "https://zrz.io/zbp/3-tenant-isolation",
      "raw_url": "https://zrz.io/zbp/3-tenant-isolation.md",
      "pinned_raw_url": "https://zrz.io/zbp/3-tenant-isolation/v1.md"
    },
    {
      "id": 4,
      "ref": "ZBP-4",
      "title": "Authentication for a multi-tenant SaaS product",
      "version": "1.0.0",
      "major": 1,
      "status": "stable",
      "date": "2026-07-27",
      "updated": null,
      "authors": [
        "Theo Zourzouvillys"
      ],
      "tags": [
        "security",
        "saas",
        "auth",
        "identity",
        "sso",
        "multi-tenancy"
      ],
      "summary": "A complete specification for SaaS authentication: one global user, explicit per-org membership, server-authoritative sessions that die with membership, SSO enforcement that closes every side door, scoped invitations, org-owned API keys, and audited support access.",
      "use_when": "You are building sign-in for a product where people belong to customer organisations, and one person may belong to several.",
      "not_for": [
        "Service-to-service authentication — workloads should get tokens from an STS, not sign in.",
        "Authorisation inside an organisation; this establishes who the caller is and which org they act in, not what they may do to a given record.",
        "Consumer products with no organisation concept, where the org model is pure overhead."
      ],
      "requires": [
        {
          "id": 1,
          "ref": "ZBP-1",
          "title": "DPoP-bound requests across an API surface",
          "url": "https://zrz.io/zbp/1-dpop-bound-requests"
        },
        {
          "id": 3,
          "ref": "ZBP-3",
          "title": "Tenant isolation in a multi-tenant system",
          "url": "https://zrz.io/zbp/3-tenant-isolation"
        }
      ],
      "provides": [
        "saas-authentication",
        "organization-membership",
        "session-management"
      ],
      "implements_notes": [
        {
          "id": 8,
          "ref": "ZFN-8",
          "url": "https://zrz.io/zfn/8"
        },
        {
          "id": 10,
          "ref": "ZFN-10",
          "url": "https://zrz.io/zfn/10"
        },
        {
          "id": 27,
          "ref": "ZFN-27",
          "url": "https://zrz.io/zfn/27"
        },
        {
          "id": 37,
          "ref": "ZFN-37",
          "url": "https://zrz.io/zfn/37"
        },
        {
          "id": 38,
          "ref": "ZFN-38",
          "url": "https://zrz.io/zfn/38"
        },
        {
          "id": 40,
          "ref": "ZFN-40",
          "url": "https://zrz.io/zfn/40"
        }
      ],
      "supersedes": null,
      "superseded_by": null,
      "aliases": [],
      "requirements": {
        "count": 52,
        "ids": [
          "ZBP-4-R1",
          "ZBP-4-R2",
          "ZBP-4-R3",
          "ZBP-4-R4",
          "ZBP-4-R5",
          "ZBP-4-R6",
          "ZBP-4-R7",
          "ZBP-4-R8",
          "ZBP-4-R9",
          "ZBP-4-R10",
          "ZBP-4-R11",
          "ZBP-4-R12",
          "ZBP-4-R13",
          "ZBP-4-R14",
          "ZBP-4-R15",
          "ZBP-4-R16",
          "ZBP-4-R17",
          "ZBP-4-R18",
          "ZBP-4-R19",
          "ZBP-4-R20",
          "ZBP-4-R21",
          "ZBP-4-R22",
          "ZBP-4-R23",
          "ZBP-4-R24",
          "ZBP-4-R25",
          "ZBP-4-R26",
          "ZBP-4-R27",
          "ZBP-4-R28",
          "ZBP-4-R29",
          "ZBP-4-R30",
          "ZBP-4-R31",
          "ZBP-4-R32",
          "ZBP-4-R33",
          "ZBP-4-R34",
          "ZBP-4-R35",
          "ZBP-4-R36",
          "ZBP-4-R37",
          "ZBP-4-R38",
          "ZBP-4-R39",
          "ZBP-4-R40",
          "ZBP-4-R41",
          "ZBP-4-R42",
          "ZBP-4-R43",
          "ZBP-4-R44",
          "ZBP-4-R45",
          "ZBP-4-R46",
          "ZBP-4-R47",
          "ZBP-4-R48",
          "ZBP-4-R49",
          "ZBP-4-R50",
          "ZBP-4-R51",
          "ZBP-4-R52"
        ]
      },
      "content_sha256": "bc6c194b9736a20d24ee3deb655fefb8a1104dc017d8f6f4f5b6dae4dd1d0a03",
      "source": "src/content/blueprints/4-multi-tenant-saas-authentication.md",
      "url": "https://zrz.io/zbp/4-multi-tenant-saas-authentication",
      "raw_url": "https://zrz.io/zbp/4-multi-tenant-saas-authentication.md",
      "pinned_raw_url": "https://zrz.io/zbp/4-multi-tenant-saas-authentication/v1.md"
    }
  ]
}