PHPackages                             provemark/content-credentials - PHPackages - PHPackages  [Skip to content](#main-content)[PHPackages](/)[Directory](/)[Categories](/categories)[Trending](/trending)[Leaderboard](/leaderboard)[Changelog](/changelog)[Analyze](/analyze)[Collections](/collections)[Log in](/login)[Sign up](/register)

1. [Directory](/)
2. /
3. provemark/content-credentials

ActiveLibrary

provemark/content-credentials
=============================

PHP library for C2PA Content Credentials: build, sign, read and verify manifests, with machine-readable marking of AI-generated content (EU AI Act, Article 50).

v0.2.0(today)01↑2900%MITPHPPHP ^8.3CI passing

Since Jul 27Pushed todayCompare

[ Source](https://github.com/provemark/content-credentials)[ Packagist](https://packagist.org/packages/provemark/content-credentials)[ Docs](https://github.com/provemark/content-credentials)[ RSS](/packages/provemark-content-credentials/feed)WikiDiscussions main Synced today

READMEChangelog (2)Dependencies (16)Versions (3)Used By (0)

Content Credentials
===================

[](#content-credentials)

[![CI](https://github.com/provemark/content-credentials/actions/workflows/ci.yml/badge.svg)](https://github.com/provemark/content-credentials/actions/workflows/ci.yml)[![Latest Version](https://camo.githubusercontent.com/401f720b1b84401812e18c914fefc7bd65134c963b9315648669c3c124848848/68747470733a2f2f696d672e736869656c64732e696f2f7061636b61676973742f762f70726f76656d61726b2f636f6e74656e742d63726564656e7469616c73)](https://packagist.org/packages/provemark/content-credentials)[![PHP Version](https://camo.githubusercontent.com/bca69d3fed456e791b18070bab206cd22899c4761a0c73dec10850f06550082f/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f7068702d253545382e332d373737626234)](composer.json)[![License: MIT](https://camo.githubusercontent.com/f8df3091bbe1149f398a5369b2c39e896766f9f6efba3477c63e9b4aa940ef14/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f6c6963656e73652d4d49542d677265656e)](LICENSE)

A PHP library for **C2PA Content Credentials**: build, sign, read and verify manifests for media assets. Its primary purpose is the machine-readable marking of **AI-generated content** required by the **EU AI Act, Article 50** — a `c2pa.actions.v2` / `c2pa.created` assertion with `digitalSourceType = trainedAlgorithmicMedia`.

It ships as two pieces:

- a **framework-agnostic Core** (`Provemark\ContentCredentials\Core\*`) that builds manifests and talks to a signing service over HTTP (PSR-18), and
- an optional **Laravel integration** (`Provemark\ContentCredentials\Laravel\*`) — a service provider + facade that wires everything from config.

**The private signing key never touches your web application.** Signing is delegated to a small **Node signing service** (`service/`, based on `@contentauth/c2pa-node`) that you run separately — keeping the key isolated from the app process, the pattern the CAI's own tooling uses. (This is the deliberate trade-off versus an in-process native extension, which puts the key on the web server.)

> **Status:** this is a spec-driven rebuild of a proven end-to-end spike. The design, decisions and trade-offs are documented in [`specs/`](specs/), [`docs/`](docs/) and [`NOTES.md`](NOTES.md).

Requirements
------------

[](#requirements)

- PHP **8.3+**
- A **PSR-18 HTTP client** and **PSR-17 factories**. In Laravel these are discovered automatically (Guzzle ships with Laravel); in plain PHP you inject your own.
- The **signing service** running (see [Signing service](#signing-service)).

Installation
------------

[](#installation)

```
composer require provemark/content-credentials
```

For the latest unreleased changes, require the `main` branch:

```
composer require provemark/content-credentials:dev-main
```

In **Laravel** the service provider and `ContentCredentials` facade are registered automatically (package auto-discovery). Publish the config if you want to tweak it:

```
php artisan vendor:publish --tag=content-credentials-config
```

Set the service location and shared secret in your `.env`:

```
CONTENTAUTH_SERVICE_URL=http://localhost:3000
CONTENTAUTH_API_KEY=your-shared-secret
```

Quick start (Laravel)
---------------------

[](#quick-start-laravel)

```
use Provemark\ContentCredentials\Core\Manifest\ManifestBuilder;
use Provemark\ContentCredentials\Core\Manifest\MediaType;
use Provemark\ContentCredentials\Core\Signing\Asset;
use Provemark\ContentCredentials\Laravel\ContentCredentials;

$bytes = file_get_contents('image.png');

// 1. Describe the asset as AI-generated (EU AI Act Art. 50 marking).
$manifest = ManifestBuilder::forAiGeneratedImage(MediaType::Png)
    ->withSoftwareAgent('ACME GenAI Image Model', '3.1.0')
    ->withClaimGenerator(config('app.name'), '1.0.0')
    ->build();

// 2. Sign it via the service.
$signed = ContentCredentials::sign(new Asset($bytes, MediaType::Png), $manifest);
file_put_contents('signed.png', $signed->bytes); // never re-encode these bytes

// 3. Read the credential back.
$report = ContentCredentials::read(new Asset($signed->bytes, MediaType::Png));

$report->isAiGenerated();        // true
$report->digitalSourceTypes();   // ['http://cv.iptc.org/newscodes/digitalsourcetype/trainedAlgorithmicMedia']
$report->signer()?->issuer;      // e.g. "C2PA Test Signing Cert"
```

Quick start (plain PHP / any framework)
---------------------------------------

[](#quick-start-plain-php--any-framework)

Core depends only on PSR interfaces — inject any PSR-18 client and PSR-17 factories:

```
use Provemark\ContentCredentials\Core\Manifest\ManifestBuilder;
use Provemark\ContentCredentials\Core\Manifest\MediaType;
use Provemark\ContentCredentials\Core\Signing\Asset;
use Provemark\ContentCredentials\Core\Signing\SigningServiceConfig;
use Provemark\ContentCredentials\Core\Signing\SigningServiceSigner;
use GuzzleHttp\Client;                       // any PSR-18 client
use Nyholm\Psr7\Factory\Psr17Factory;        // any PSR-17 factory

$factory = new Psr17Factory();
$signer = new SigningServiceSigner(
    new Client(),
    $factory,
    $factory,
    new SigningServiceConfig('http://localhost:3000', getenv('CONTENTAUTH_API_KEY')),
);

$manifest = ManifestBuilder::forAiGeneratedImage(MediaType::Jpeg)
    ->withSoftwareAgent('ACME GenAI Image Model', '3.1.0')
    ->build();

$signed = $signer->sign(new Asset(file_get_contents('in.jpg'), MediaType::Jpeg), $manifest);
file_put_contents('out.jpg', $signed->bytes);
```

Reading works the same way with `SigningServiceReader` → `ManifestReport`.

Supported formats in this version: **PNG and JPEG**.

Signing service
---------------

[](#signing-service)

The service holds the signing key and performs the C2PA operation. Run it with Docker Compose using the bundled **c2pa-rs ES256 test certificates**:

```
cp .env.example .env          # set a CONTENTAUTH_API_KEY value

# The private test key is intentionally NOT committed. Fetch the c2pa-rs sample
# key for local development (test material only — never a real key):
curl -sfSL https://raw.githubusercontent.com/contentauth/c2pa-rs/main/cli/sample/es256_private.key \
  -o certs/es256_private.key

docker compose up -d --build  # service on http://localhost:3000
```

`POST /v1/sign` and `POST /v1/read` are Bearer-authenticated with `CONTENTAUTH_API_KEY`; `GET /health` is public.

Verifying the output
--------------------

[](#verifying-the-output)

`bin/verify.sh` runs [`c2patool`](https://github.com/contentauth/c2pa-rs) with the test trust settings and reports signature validity, cert trust and the AI marking:

```
bin/verify.sh out/signed.png
# Signature valid: PASS   Cert trusted: PASS   AI Art.50 mark: PASS
```

Note: test certificates produce a cryptographically **valid signature** but are not on any production trust list — "valid signature" is not the same as "trusted certificate". See [`docs/c2pa-primer.md`](docs/c2pa-primer.md) §5.

Development
-----------

[](#development)

```
composer install
composer check   # Pint (style) + PHPStan (level max) + Pest + Deptrac
```

`composer check` is the single definition of green. The architecture boundary (`Core` must not depend on Laravel/Illuminate) is enforced by Deptrac.

To exercise the whole chain against a **running** service with the real library code (build → sign → read → c2patool verify):

```
docker compose up -d --build   # service must be running (see above)
php bin/e2e.php                 # signs tests/fixture.png -> out/signed.png, then verifies
```

Security
--------

[](#security)

- **Never commit real private keys or production certificates.** `certs/` and the tests use c2pa-rs **test** material only; `es256_private.key` is gitignored. Trust-settings files contain only public test CA certs.
- The `CONTENTAUTH_API_KEY` and service URL come from the environment; the library never logs the token or key material.
- All manifest/service input is treated as untrusted and validated.

License
-------

[](#license)

[MIT](LICENSE) © Maurice van Loon

###  Health Score

38

—

LowBetter than 83% of packages

Maintenance100

Actively maintained with recent releases

Popularity2

Limited adoption so far

Community6

Small or concentrated contributor base

Maturity39

Early-stage or recently created project

 Bus Factor1

Top contributor holds 100% of commits — single point of failure

How is this calculated?**Maintenance (25%)** — Last commit recency, latest release date, and issue-to-star ratio. Uses a 2-year decay window.

**Popularity (30%)** — Total and monthly downloads, GitHub stars, and forks. Logarithmic scaling prevents top-heavy scores.

**Community (15%)** — Contributors, dependents, forks, watchers, and maintainers. Measures real ecosystem engagement.

**Maturity (30%)** — Project age, version count, PHP version support, and release stability.

###  Release Activity

Cadence

Every ~0 days

Total

2

Last Release

0d ago

### Community

Maintainers

![](https://avatars.githubusercontent.com/u/16209371?v=4)[Maurice](/maintainers/Maurice1969DB)[@Maurice1969DB](https://github.com/Maurice1969DB)

---

Top Contributors

[![Maurice1969DB](https://avatars.githubusercontent.com/u/16209371?v=4)](https://github.com/Maurice1969DB "Maurice1969DB (30 commits)")

---

Tags

ai-generatedc2pacontent-authenticitycontent-credentialseu-ai-actlaravelphpprovenancelaravelprovenanceeu-ai-actc2pacontent-credentialscontent-authenticityai-generated

###  Code Quality

TestsPest

Static AnalysisPHPStan

Code StyleLaravel Pint

Type Coverage Yes

### Embed Badge

![Health badge](/badges/provemark-content-credentials/health.svg)

```
[![Health](https://phpackages.com/badges/provemark-content-credentials/health.svg)](https://phpackages.com/packages/provemark-content-credentials)
```

###  Alternatives

[telnyx/telnyx-php

Official Telnyx PHP SDK — APIs for Voice, SMS, MMS, WhatsApp, Fax, SIP Trunking, Wireless IoT, Call Control, and more. Build global communications on Telnyx's private carrier-grade network.

36789.4k2](/packages/telnyx-telnyx-php)[flow-php/flow

PHP ETL - Extract Transform Load - Data processing framework

85036.3k](/packages/flow-php-flow)[tempest/framework

The PHP framework that gets out of your way.

2.2k34.4k16](/packages/tempest-framework)[gotenberg/gotenberg-php

A PHP client for interacting with Gotenberg, a developer-friendly API for converting numerous document formats into PDF files, and more!

3896.2M31](/packages/gotenberg-gotenberg-php)[getbrevo/brevo-php

Official Brevo provided RESTFul API V3 php library

1003.9M50](/packages/getbrevo-brevo-php)[laudis/neo4j-php-client

Neo4j-PHP-Client is the most advanced PHP Client for Neo4j

185702.8k44](/packages/laudis-neo4j-php-client)

PHPackages © 2026

[Directory](/)[Categories](/categories)[Trending](/trending)[Changelog](/changelog)[Analyze](/analyze)
