A proof-of-concept application demonstrating how to sign and verify media files using the C2PA (Coalition for Content Provenance and Authenticity) standard. This project consists of a serverless API backend for signing files and a React web interface for inspecting C2PA manifests client-side.
C2PA is an open technical standard that enables cryptographically verifiable metadata to be embedded in media files (images, videos, etc.). This POC demonstrates:
- Server-side signing: Upload images to AWS S3 and sign them with C2PA manifests using test certificates
- Client-side verification: Inspect C2PA manifests directly in the browser and validate their integrity
- Full workflow: Complete end-to-end flow from file upload to signed file download
┌─────────────┐ ┌──────────────┐ ┌─────────────┐
│ Web UI │────────▶│ API Gateway │────────▶│ Lambda │
│ (React) │ │ │ │ Functions │
└─────────────┘ └──────────────┘ └─────────────┘
│ │
│ │
└──────────────┐ |
│ │
┌─────────────┐ ┌─────────────┐
│ C2PA Toolkit │ │ S3 │
│ (WASM) │ │ Bucket │
└─────────────┘ └─────────────┘
Serverless backend built with AWS SAM that provides:
- Sign endpoint: Signs files uploaded to S3 with C2PA manifests
- Verify endpoint: Verifies C2PA signatures on files stored in S3
- Presigned URL endpoint: Generates presigned URLs for direct S3 uploads
React application that provides:
- C2PA Inspector: Upload and inspect media files for C2PA manifests
- Signing Interface: Upload images, add custom claims, and download signed files
- Validation Status: Visual indicators for valid/invalid/no manifest found
- Node.js 22.x or higher
- npm or yarn
- AWS CLI configured with appropriate credentials
- AWS SAM CLI for deploying the API
- AWS Account with permissions to create:
- Lambda functions
- API Gateway APIs
- S3 buckets
- IAM roles and policies
git clone <repository-url>
cd c2pa-pocThis POC uses test certificates provided by C2PA for demonstration purposes. The certificates are automatically included with the C2PA toolkit and do not require any additional setup.
cd api
# Install dependencies
npm install
# Build TypeScript
npm run build
# Deploy to AWS (ensure AWS credentials are configured)
npm run sam:deployThe deployment will create:
- Lambda functions for sign, verify, and presigned-url endpoints
- API Gateway REST API
- S3 bucket for file storage
- IAM roles and policies
- API key for authentication
After deployment, note the API base URL and API key from the CloudFormation outputs.
cd webui
# Install dependencies
npm install
# Create environment file
cp .env.example .env
# Edit .env and add:
# VITE_API_URL=https://your-api-id.execute-api.region.amazonaws.com/v1
# VITE_API_KEY=your-api-key-id
# Start development server
npm run dev-
Inspect C2PA Manifests:
- Open the application in your browser
- Click "Choose File" and select a media file (JPEG, PNG, etc.)
- The inspector will display:
- Validation status (valid/invalid/no manifest)
- Full manifest data in JSON format
- File metadata and preview
-
Sign an Image:
- Click "Test Sign an image" button
- Select an image file (JPG or PNG)
- Optionally add custom claims as JSON (e.g.,
{"camera": "Canon EOS R5", "location": "San Francisco"}) - Click "Upload & Sign"
- Download the signed file when ready
Get a presigned URL for uploading a file to S3.
Query Parameters:
filename(required): Name of the file to uploadexpiresIn(optional): URL expiration in seconds (60-604800, default: 3600)
Response:
{
"ok": true,
"presignedUrl": "https://s3.amazonaws.com/...",
"key": "uploads/1234567890-example.jpg",
"filename": "example.jpg",
"contentType": "image/jpeg",
"expiresIn": 3600,
"expiresAt": "2024-01-01T12:00:00.000Z"
}Sign a file that has been uploaded to S3.
Request Body:
{
"s3Key": "uploads/1234567890-example.jpg",
"claims": {
"camera": "Canon EOS R5",
"location": "San Francisco"
}
}Response:
{
"ok": true,
"s3Keys": {
"original": "uploads/1234567890-example.jpg",
"signed": "signed/signed-1234567890-example.jpg"
},
"downloadUrls": {
"original": "https://s3.amazonaws.com/...",
"signed": "https://s3.amazonaws.com/...",
"expiresIn": 3600,
"expiresAt": "2024-01-01T12:00:00.000Z"
},
"verification": {
"valid": true,
"validation_status": "success",
"manifest": { ... }
}
}Verify a C2PA-signed file in S3.
Request Body:
{
"s3Key": "signed/signed-1234567890-example.jpg"
}Response:
{
"ok": true,
"s3Key": "signed/signed-1234567890-example.jpg",
"downloadUrl": {
"url": "https://s3.amazonaws.com/...",
"expiresIn": 3600,
"expiresAt": "2024-01-01T12:00:00.000Z"
},
"verification": {
"valid": true,
"validation_status": "success",
"manifest": { ... }
}
}All endpoints require API key authentication via x-api-key header.
c2pa-poc/
├── api/ # Serverless API backend
│ ├── src/
│ │ ├── sign.ts # Sign endpoint handler
│ │ ├── verify.ts # Verify endpoint handler
│ │ ├── presigned-url.ts # Presigned URL endpoint handler
│ │ ├── utils-c2pa.ts # C2PA signing/verification utilities
│ │ ├── common/
│ │ │ ├── http.ts # HTTP response utilities
│ │ │ └── crypto.ts # Cryptographic utilities
│ │ └── options-handler.ts # CORS OPTIONS handler
│ ├── template.yaml # AWS SAM template
│ ├── package.json
│ └── tsconfig.json
│
├── webui/ # React web application
│ ├── src/
│ │ ├── App.tsx # Main application component
│ │ ├── C2PAInspector.tsx # C2PA manifest inspector
│ │ ├── SignModal.tsx # File signing modal
│ │ ├── axios-client.ts # API client configuration
│ │ └── main.tsx # Application entry point
│ ├── public/
│ │ └── c2pa/ # C2PA toolkit WASM and worker files
│ ├── package.json
│ └── vite.config.ts
│
└── README.md # This file
- TypeScript: Type-safe codebase
- AWS SAM: Serverless application model
- AWS Lambda: Serverless compute
- AWS API Gateway: REST API
- AWS S3: File storage
- c2pa-node: Node.js C2PA SDK (
@c2pa/c2pa-node)
- React: UI framework
- TypeScript: Type-safe codebase
- Vite: Build tool and dev server
- TailwindCSS + DaisyUI: Styling
- @contentauth/react: React hooks for C2PA
- c2pa: C2PA toolkit for browser (WASM)
- Axios: HTTP client
- JPEG/JPG
- PNG
- WebP
- TIFF/TIF
- MP4 (video)
- QuickTime MOV (video)
- Any format supported by the C2PA toolkit
- Inspector supports: JPEG, PNG, TIFF
# API tests (if available)
cd api
npm test
# Web UI tests (if available)
cd webui
npm test# Build API
cd api
npm run build
# Build Web UI
cd webui
npm run build# API
cd api
npm run lint
# Web UI
cd webui
npm run lint- Lambda timeout: Increase timeout in
template.yamlif processing large files - S3 access denied: Check IAM role permissions in
template.yaml
- C2PA toolkit not loading: Ensure
toolkit_bg.wasmandc2pa.worker.jsare in/public/c2pa/ - API connection errors: Verify
VITE_API_URLandVITE_API_KEYare correctly set - CORS errors: Ensure API CORS configuration allows your domain
MIT License - see LICENSE file for details
This is a proof-of-concept project. Contributions, issues, and pull requests are welcome!
Built using the official C2PA toolkits and SDKs provided by the Coalition for Content Provenance and Authenticity.