Announcement

Introducing provemark: C2PA Content Credentials for PHP

PHP finally has a first-class way to build, sign, read and verify C2PA Content Credentials — including the machine-readable marking of AI-generated content that the EU AI Act, Article 50, will require. It is open source, framework-agnostic, and ships with a working signing service so you can prove the whole chain on your own machine today.

The gap

Content Credentials — the C2PA standard behind the "CR" pin you now see on images from Adobe, Leica, and a growing list of cameras and generators — is how a piece of media carries a signed, tamper-evident record of where it came from. The tooling around it is real and maturing fast, but it grew up in JavaScript, Rust and Python. If your application is written in PHP — and a large share of the web's publishing, CMS and media platforms are — there was no maintained, idiomatic way in.

That gap is about to matter to a lot of people. The EU AI Act, Article 50 requires providers of generative-AI systems to mark their output as artificially generated in a machine-readable way. C2PA is the mechanism the industry is converging on to do exactly that. A PHP shop that needs to comply shouldn't have to shell out to a foreign runtime or reverse-engineer a manifest format to get there.

provemark/content-credentials is a small, spec-driven PHP library that closes that gap: build a manifest, sign it, read it back, and verify it — with the AI-generated marking as a first-class feature, not an afterthought.

What it does

The library is built around the full lifecycle, verified end-to-end against a real signature that c2patool accepts:

A framework-agnostic core does the work; a thin Laravel integration (service provider, facade, queued jobs, artisan commands) wires it into an app with a config file and nothing else. The core has no framework dependency at all — the boundary is enforced in CI, not just by convention.

composer require provemark/content-credentials

The Article 50 marking, done right

Marking content as AI-generated in C2PA is deceptively subtle. It is a single actions assertion whose first action is c2pa.created, carrying a digitalSourceType set to the full IPTC URI for algorithmically-generated media, plus the name of the tool that made it. Get the label or the URI slightly wrong and the manifest is either malformed or silently fails to say what you meant.

provemark treats that assertion as the core use case and gets it right by construction — one correct actions assertion, no duplicates, well-formed under claim v2. That is the difference between "we embedded some metadata" and "a verifier will actually report this as AI-generated."

Two decisions worth knowing about

The signing key is isolated. Signing happens behind a small HTTP service that holds the private key; the PHP application talks to it over a narrow, authenticated contract and never touches key material itself. This is the single most important architectural property for a credential system — it means a compromise of your web tier does not hand an attacker your signing identity. The library ships that service as a working reference implementation.

It is spec-driven. Every feature exists as a written specification with tests before a line of implementation. That is unusual for a young open-source library, and deliberate: provenance tooling is exactly the kind of software where "it seemed to work" is not good enough, and where a reader needs to trust that behaviour is pinned down, not incidental.

Where to start

It is early days, and I would rather have a handful of careful users than a splash. If you work with media provenance, AI-generated-content compliance, or just want C2PA in a PHP stack, I would genuinely like to hear what breaks and what is missing.

Try it, read the specs, and tell me where it falls short — provemark/content-credentials on GitHub, provemark/content-credentials on Packagist. Issues and discussions are open.