Background
FAIR aggregators serving PHP ecosystem packages MAY expose a Composer-compatible repository API so that Composer can use them as a package source without FAIR-specific client changes. This is optional — the FAIR protocol does not require aggregators to implement Composer support, and aggregators serving non-PHP ecosystems have no reason to do so. This spec section defines what a conforming implementation looks like for those that choose to. (A proof-of-concept implementing this flow for TYPO3 was developed at the CloudFest Hackathon 2026.)
Depends on:
Proposed additions to specification.md
Add a new top-level section after the Caching section.
Composer-Compatible Aggregator API
FAIR aggregators serving PHP ecosystem packages MAY expose a Composer-compatible repository API to allow Composer clients to discover and install FAIR packages without requiring FAIR-specific Composer configuration.
Aggregators implementing this API MUST only expose packages whose FAIR Metadata Document includes a composer-name field. The composer-name value is used as the Composer package name in all API responses.
Required Endpoints
GET /packages.json
The repository root document, conforming to the Composer v2 repository format using metadata-url lazy-loading:
{
"packages": {},
"metadata-url": "/p2/%package%.json",
"search": "/search.json?q=%query%&type=%type%"
}
GET /p2/{vendor}/{package}.json
Per-package metadata in Packagist v2 format. The response MUST include all available versions of the package.
Each version entry MUST include:
name — the composer-name from the Metadata Document
version — the version string from the Release Document
dist.url — the artifact URL from the FAIR release record (see Artifact URL below)
dist.type — the string fair-zip
dist.shasum — the hex portion of the checksum value from the FAIR release record, with the algorithm prefix and colon removed (e.g. sha256:abc123... becomes abc123...)
extra.fair.package-meta.did — the package DID (note: extra.fair.package-meta is the structure FAIR clients read at install time; the rename from the flat extra.fair.{did,checksum,signature} used in the CloudFest proof of concept is tracked separately in the implementation repositories)
extra.fair.package-meta.checksum — the full checksum string from the FAIR release record, including the algorithm prefix
extra.fair.package-meta.signature — the signature string from the FAIR release record
require — the Composer require map derived from the release record (see Dependency Mapping below)
Example package record:
{
"name": "acme/my-extension",
"version": "1.2.0",
"type": "typo3-cms-extension",
"dist": {
"url": "https://example.com/releases/my-extension-1.2.0.zip",
"type": "fair-zip",
"shasum": "8a961a087530195bdb7d7ba491e082fbd3dbf1cbe1f66b6d613e99739e5dfeb1"
},
"extra": {
"fair": {
"package-meta": {
"did": "did:plc:abc123...",
"checksum": "sha256:8a961a087530195bdb7d7ba491e082fbd3dbf1cbe1f66b6d613e99739e5dfeb1",
"signature": "zRL37AsydcAr2CZFkM12pL..."
}
}
},
"require": {
"php": ">=8.1",
"typo3/cms-core": "^12.4 || ^13.0"
}
}
Dependency Mapping
When building the require map for a Composer package record, aggregators MUST apply the following base mappings from the FAIR release record's requires field:
FAIR requires key |
Composer require key |
env:php |
php |
env:php-{name} |
ext-{name} |
DID key where composer-name is known |
that composer-name value |
Ecosystem extensions MAY define additional mappings for their env:* keys (for example, env:typo3 → typo3/cms-core and env:wp → roots/wordpress as registered in the env key registry). Aggregators SHOULD apply any such mappings defined for the package types they serve.
Entries in x-composer-requires MUST be included in the require map verbatim, as they are already in Composer format.
DID keys where no composer-name is known MUST be omitted from the require map. Aggregators SHOULD log or surface these omissions so that missing composer-name registrations can be identified.
Artifact URL
The dist.url in each package record MUST be the artifact URL from the FAIR release record, pointing directly to the origin artifact. Aggregators MUST NOT substitute a proxied URL. The artifact URL is part of the signed release record; substituting it would prevent signature verification by FAIR clients that re-derive the expected URL from the FAIR metadata.
Checksum Field Invariant
dist.shasum and extra.fair.package-meta.checksum MUST be derived from the same value in the FAIR release record. Aggregators MUST NOT compute dist.shasum independently. The derivation is:
dist.shasum = hex portion of release.checksum (after ":")
extra.fair.package-meta.checksum = release.checksum verbatim
dist.type Policy
Aggregators MUST set dist.type to fair-zip in all package records. Standard Composer clients that are not FAIR-aware will refuse to install packages with an unknown dist type, which is the correct behaviour — FAIR package verification requires a FAIR client. Aggregators SHOULD document this requirement prominently so that users understand why a FAIR client is required.
Trust Model
The Composer repository protocol trusts at the repository level (HTTPS). FAIR's per-artifact signatures provide an independent trust layer on top of this. When a FAIR client installs a package from a FAIR aggregator via Composer:
- Composer fetches package metadata from the aggregator via HTTPS.
- Composer downloads the artifact from
dist.url directly from the origin.
- The FAIR client verifies
dist.shasum (integrity) and the Ed25519 signature in extra.fair.package-meta.signature against the signing keys in the DID document (provenance).
Step 3 is independent of step 1. A tampered aggregator response that substitutes dist.url or extra.fair.package-meta will fail at step 3: a different URL points to different bytes which will not match the checksum; a substituted checksum or signature will not validate against the DID's signing keys.
Composer clients that are not FAIR-aware receive integrity checking via dist.shasum only, with no provenance verification. Aggregators SHOULD document that FAIR provenance verification requires a FAIR client.
Reverse Lookup Endpoint
Aggregators implementing this API MUST expose a reverse lookup endpoint for build tools that need to translate Composer package names to FAIR DIDs:
GET /api/composer-did?package={vendor}/{name}
Response:
{
"package": "acme/my-extension",
"did": "did:plc:abc123..."
}
Returns HTTP 404 if no FAIR DID is known for the given package name.
Background
FAIR aggregators serving PHP ecosystem packages MAY expose a Composer-compatible repository API so that Composer can use them as a package source without FAIR-specific client changes. This is optional — the FAIR protocol does not require aggregators to implement Composer support, and aggregators serving non-PHP ecosystems have no reason to do so. This spec section defines what a conforming implementation looks like for those that choose to. (A proof-of-concept implementing this flow for TYPO3 was developed at the CloudFest Hackathon 2026.)
Depends on:
compatibilityto Release Document)composer-name,x-composer-requires,x-composer-repositories, and env key registry)Proposed additions to
specification.mdAdd a new top-level section after the Caching section.
Composer-Compatible Aggregator API
FAIR aggregators serving PHP ecosystem packages MAY expose a Composer-compatible repository API to allow Composer clients to discover and install FAIR packages without requiring FAIR-specific Composer configuration.
Aggregators implementing this API MUST only expose packages whose FAIR Metadata Document includes a
composer-namefield. Thecomposer-namevalue is used as the Composer package name in all API responses.Required Endpoints
GET /packages.json
The repository root document, conforming to the Composer v2 repository format using
metadata-urllazy-loading:{ "packages": {}, "metadata-url": "/p2/%package%.json", "search": "/search.json?q=%query%&type=%type%" }GET /p2/{vendor}/{package}.json
Per-package metadata in Packagist v2 format. The response MUST include all available versions of the package.
Each version entry MUST include:
name— thecomposer-namefrom the Metadata Documentversion— the version string from the Release Documentdist.url— the artifact URL from the FAIR release record (see Artifact URL below)dist.type— the stringfair-zipdist.shasum— the hex portion of thechecksumvalue from the FAIR release record, with the algorithm prefix and colon removed (e.g.sha256:abc123...becomesabc123...)extra.fair.package-meta.did— the package DID (note:extra.fair.package-metais the structure FAIR clients read at install time; the rename from the flatextra.fair.{did,checksum,signature}used in the CloudFest proof of concept is tracked separately in the implementation repositories)extra.fair.package-meta.checksum— the full checksum string from the FAIR release record, including the algorithm prefixextra.fair.package-meta.signature— the signature string from the FAIR release recordrequire— the Composerrequiremap derived from the release record (see Dependency Mapping below)Example package record:
{ "name": "acme/my-extension", "version": "1.2.0", "type": "typo3-cms-extension", "dist": { "url": "https://example.com/releases/my-extension-1.2.0.zip", "type": "fair-zip", "shasum": "8a961a087530195bdb7d7ba491e082fbd3dbf1cbe1f66b6d613e99739e5dfeb1" }, "extra": { "fair": { "package-meta": { "did": "did:plc:abc123...", "checksum": "sha256:8a961a087530195bdb7d7ba491e082fbd3dbf1cbe1f66b6d613e99739e5dfeb1", "signature": "zRL37AsydcAr2CZFkM12pL..." } } }, "require": { "php": ">=8.1", "typo3/cms-core": "^12.4 || ^13.0" } }Dependency Mapping
When building the
requiremap for a Composer package record, aggregators MUST apply the following base mappings from the FAIR release record'srequiresfield:requireskeyrequirekeyenv:phpphpenv:php-{name}ext-{name}composer-nameis knowncomposer-namevalueEcosystem extensions MAY define additional mappings for their
env:*keys (for example,env:typo3→typo3/cms-coreandenv:wp→roots/wordpressas registered in the env key registry). Aggregators SHOULD apply any such mappings defined for the package types they serve.Entries in
x-composer-requiresMUST be included in therequiremap verbatim, as they are already in Composer format.DID keys where no
composer-nameis known MUST be omitted from therequiremap. Aggregators SHOULD log or surface these omissions so that missingcomposer-nameregistrations can be identified.Artifact URL
The
dist.urlin each package record MUST be the artifact URL from the FAIR release record, pointing directly to the origin artifact. Aggregators MUST NOT substitute a proxied URL. The artifact URL is part of the signed release record; substituting it would prevent signature verification by FAIR clients that re-derive the expected URL from the FAIR metadata.Checksum Field Invariant
dist.shasumandextra.fair.package-meta.checksumMUST be derived from the same value in the FAIR release record. Aggregators MUST NOT computedist.shasumindependently. The derivation is:dist.type Policy
Aggregators MUST set
dist.typetofair-zipin all package records. Standard Composer clients that are not FAIR-aware will refuse to install packages with an unknown dist type, which is the correct behaviour — FAIR package verification requires a FAIR client. Aggregators SHOULD document this requirement prominently so that users understand why a FAIR client is required.Trust Model
The Composer repository protocol trusts at the repository level (HTTPS). FAIR's per-artifact signatures provide an independent trust layer on top of this. When a FAIR client installs a package from a FAIR aggregator via Composer:
dist.urldirectly from the origin.dist.shasum(integrity) and the Ed25519 signature inextra.fair.package-meta.signatureagainst the signing keys in the DID document (provenance).Step 3 is independent of step 1. A tampered aggregator response that substitutes
dist.urlorextra.fair.package-metawill fail at step 3: a different URL points to different bytes which will not match the checksum; a substituted checksum or signature will not validate against the DID's signing keys.Composer clients that are not FAIR-aware receive integrity checking via
dist.shasumonly, with no provenance verification. Aggregators SHOULD document that FAIR provenance verification requires a FAIR client.Reverse Lookup Endpoint
Aggregators implementing this API MUST expose a reverse lookup endpoint for build tools that need to translate Composer package names to FAIR DIDs:
Response:
{ "package": "acme/my-extension", "did": "did:plc:abc123..." }Returns HTTP 404 if no FAIR DID is known for the given package name.