WP Manifestindependent plugin directory
manifest / media / wp-plugin

Content Authenticity

WordPress plugin for reading and signing C2PA content credentials (product and CAWG organisational signatures)

★ 0stars

Install

Download source zip No release zip yet

This is the repository archive. It installs, but the folder name will carry the branch suffix and updates will not flow.

Install straight from GitHub with WP-CLI:

wp plugin install https://github.com/contentauth/wp-plugin/archive/refs/heads/main.zip
No built-in updater. New versions won't appear under Dashboard → Updates. Install new releases yourself, or let Git Updater track the repository.

ContentAuth WordPress Plugin

A WordPress plugin that reads and signs C2PA content credentials, enabling conformant product signatures and CAWG organisational identity signatures.

License: Apache-2.0 OR MIT — pick whichever suits you.


Architecture

WordPress (PHP plugin)          Signing Service (Node.js)
┌────────────────────┐          ┌─────────────────────────┐
│                    │  HTTPS   │                         │
│  Media Library  ──►│─────────►│  POST /v1/sign          │
│  REST API       ──►│          │  POST /v1/read          │
│  Settings page     │◄─────────│  GET  /health           │
│                    │  signed  │                         │
└────────────────────┘  binary  │  Key Provider           │
                                │  ├── local PEM  (dev)   │
                                │  └── AWS KMS   (prod)   │
                                └─────────────────────────┘

The WordPress server never holds a private key. All cryptographic operations happen inside the signing service, which you deploy in a separate, hardened environment.

Signature types

Type What it proves Assertion label
product Content passed through a specific software product (standard C2PA claim)
cawg_org Content is associated with a named organisation cawg.identity
both Both of the above in a single manifest both

Requirements

WordPress plugin

  • PHP 8.1 or later
  • WordPress 6.3 or later

Signing service

  • Node.js 20 or later (or Docker)
  • A code-signing certificate and private key issued by a C2PA-trusted CA

Quick start

1 — Deploy the signing service

cd signing-service

# Copy and fill in the configuration
cp .env.example .env
# Set CONTENTAUTH_API_KEY, SIGNING_CERT_PATH, SIGNING_KEY_PATH

# Create the secrets directory (never commit this)
mkdir -p secrets
cp /path/to/your/signing.crt secrets/
cp /path/to/your/signing.key secrets/
chmod 400 secrets/signing.key

# Start with Docker Compose
docker compose up -d

# Verify it is healthy
curl http://localhost:3000/health

The signing service listens on port 3000 by default. Put it behind a TLS-terminating reverse proxy (nginx, Caddy, AWS ALB) before exposing it to your WP server.

2 — Install the WordPress plugin

# From the plugin directory:
composer install --no-dev

Then upload the plugin directory (or zip it) and activate it through Plugins → Installed Plugins.

3 — Configure the plugin

Go to Settings → Content Authenticity and enter:

  • Service URL — the base URL of your signing service (e.g. https://sign.example.com)
  • API Key — must match CONTENTAUTH_API_KEY in the signing service

For production, define the API key as a constant in wp-config.php instead of saving it to the database:

define( 'CONTENTAUTH_API_KEY', 'your-secret-key-here' );

Click Test signing service connection to verify connectivity.


Key management

Local PEM files (development / air-gapped)

Set KEY_PROVIDER=local and point SIGNING_CERT_PATH / SIGNING_KEY_PATH to your PEM files. The key file is cached in memory after the first read; it is never written anywhere by the service.

AWS KMS (production recommended)

Set KEY_PROVIDER=aws-kms. See signing-service/src/key-providers/aws-kms.js for the current status and integration notes.

Full KMS support (where the raw private key never exists in memory) requires an "external signer" API in c2pa-node, which is not yet available. Until then, the recommended approach for AWS users is:

  1. Store the private key as an encrypted secret in AWS Secrets Manager.
  2. Fetch and decrypt it at signing-service startup using the instance's IAM role.
  3. Hold the decrypted key in memory only (never write to disk).
  4. Rotate the key by redeploying the service.

Obtaining a code-signing certificate

Your certificate must chain to a CA recognised in the C2PA Trust List. Current options include certificates from DigiCert and other C2PA-participating CAs.

For CAWG organisational signatures, the certificate's Subject should identify your organisation.


CAWG Organisational Signatures

When signature_type is cawg_org or both, the plugin adds a cawg.identity assertion to the manifest containing:

  • Your organisation name and canonical URL (set in plugin settings)
  • An optional W3C Verifiable Credential — if your organisation has been issued one by a CAWG-recognised credential issuer, this allows validators to cryptographically verify the organisational claim

The CAWG identity assertion follows the CAWG Identity Assertion specification.


REST API

The plugin registers a REST namespace at contentauth/v1.

GET /contentauth/v1/credentials/{attachment_id}

Returns the C2PA manifest for an attachment. Append ?force=true to bypass the cache and re-read from the file.

Auth: Public for published attachments; edit_post capability for unpublished.

POST /contentauth/v1/credentials/{attachment_id}/sign

Signs an attachment. Optionally accepts signature_type in the JSON body to override the site-wide setting.

Auth: edit_post capability for the attachment.

GET /contentauth/v1/status

Returns signing service health status.

Auth: manage_options capability (administrators).


Development

PHP

composer install
composer lint         # PHP_CodeSniffer with WordPress standards
composer test         # PHPUnit

Signing service

cd signing-service
npm install
npm run dev           # auto-restarts on file changes
npm test

Security considerations

  • Never expose the signing service directly to the internet. Place it behind a private network or VPN and only allow ingress from your WordPress server.
  • Rotate the API key if it is ever compromised. Update it in both wp-config.php and the signing service environment.
  • Restrict file permissions on the signing service key file: chmod 400 signing.key.
  • Monitor the signing service logs for unexpected signing requests.
  • Rate limiting is enabled by default (60 req/min). Adjust RATE_LIMIT_PER_MINUTE for your environment.

Contributing

See CONTRIBUTING.md.

License

Licensed under either of:

at your option.