Amazon S3
Automatically back up signed PDFs to Amazon S3 when all signatures are complete.
Requirements
Section titled “Requirements”- WPsigner 2.1.0+
- An AWS account with S3 access
- An IAM user with
s3:PutObject,s3:GetObject,s3:DeleteObjectpermissions
Step 1: Create an S3 Bucket
Section titled “Step 1: Create an S3 Bucket”- Go to the AWS S3 Console
- Click Create bucket
- Choose a name and region
- Keep Block all public access enabled (recommended)
- Click Create bucket
Step 2: Create IAM Credentials
Section titled “Step 2: Create IAM Credentials”- Go to IAM → Users → Add user
- Create a user with Programmatic access
- Attach a policy with these permissions:
{ "Version": "2012-10-17", "Statement": [{ "Effect": "Allow", "Action": [ "s3:PutObject", "s3:GetObject", "s3:DeleteObject" ], "Resource": "arn:aws:s3:::YOUR-BUCKET-NAME/*" }]}- Save the Access Key ID and Secret Access Key
Store your Secret Access Key securely. AWS only shows it once during creation. If lost, you must create a new key pair.
Step 3: Configure WPsigner
Section titled “Step 3: Configure WPsigner”- Go to WPsigner → Integrations → Amazon S3
- Enter your Access Key ID and Secret Access Key
- Enter your bucket name and select the region
- Optionally change the path prefix (default:
wpsigner/) - Click Test Connection to verify
- Click Save Settings
How It Works
Section titled “How It Works”When all signers complete their signatures, WPsigner uploads the signed PDF to your S3 bucket using AWS Signature V4 authentication.
| Event | Action |
|---|---|
| All signatures complete | PDF uploaded to s3://bucket/prefix/Title_Date_ID.pdf |
Upload Path
Section titled “Upload Path”The object key is built from the path prefix and a generated file name:
{path_prefix}{sanitized_title}_{date}_{document_id}.pdf| Segment | Example | Description |
|---|---|---|
{path_prefix} | wpsigner/ | Configurable in settings (default: wpsigner/). Trailing slash is enforced automatically. |
{sanitized_title} | Service-Agreement | Document title, sanitized for safe file names |
{date} | 2026-03-06 | Signing date in Y-m-d format |
{document_id} | 142 | Internal WPsigner document ID |
Full key example:
wpsigner/Service-Agreement_2026-03-06_142.pdfAfter a successful upload, WPsigner stores a cloud backup reference in the database with the object key, provider name, and upload timestamp. This metadata powers the download feature in the admin panel.
Use Cases
Section titled “Use Cases”| Scenario | Configuration |
|---|---|
| Long-term document archival | Use S3 Standard or S3 Glacier for cost-efficient retention |
| Compliance storage with immutability | Enable S3 Object Lock on the bucket |
| Multi-region redundancy | Enable cross-region replication on the bucket |
| Cost-optimized backup | Pair with S3 Lifecycle rules to transition older files to Glacier |
| Multi-cloud strategy | Combine with Dropbox or OneDrive |
| Custom folder structure | Use the wps_s3_backup_key filter to organize by date, client, or category |
Compatibility
Section titled “Compatibility”| Component | Supported Versions |
|---|---|
| WPsigner | 2.1.0+ |
| WordPress | 6.0+ |
| PHP | 7.4+ |
| AWS Signature | V4 |
| S3 Regions | All 21 standard AWS regions |
| S3 Storage Classes | Standard, Intelligent-Tiering, Glacier (via lifecycle rules) |
| Max file size | Limited by PHP memory_limit (single PUT upload) |
| Multisite | Supported (per-site configuration) |
Security
Section titled “Security”| Feature | Details |
|---|---|
| AWS Signature V4 | Requests signed per AWS standard |
| AES-256-GCM | Secret key encrypted at rest in database |
| Minimal Permissions | Only PutObject, GetObject, DeleteObject needed |
| Rate Limiting | Test: 5/min, Save: 10/min per user |
| Nonce Verification | All AJAX requests verified |
Troubleshooting
Section titled “Troubleshooting”| Issue | Cause | Solution |
|---|---|---|
AccessDenied (403) | IAM policy missing required actions | Verify s3:PutObject is granted on the correct bucket ARN |
NoSuchBucket (404) | Bucket name is wrong or bucket was deleted | Double-check the bucket name in WPsigner settings |
InvalidAccessKeyId | Access Key is incorrect or deactivated | Verify the Access Key in IAM Console; create a new one if deactivated |
SignatureDoesNotMatch | Secret key is incorrect or corrupted | Re-enter the Secret Access Key and save |
RequestTimeTooSkewed | Server clock is more than 15 minutes off | Sync your server clock with NTP (ntpdate pool.ntp.org) |
| “Security check failed” | Nonce expired | Refresh the page and retry |
| ”Too many requests” | Rate limit exceeded | Wait 60 seconds and retry |
| ”Failed to sign request” | Credentials not configured or decryption failed | Re-enter both the Access Key and Secret Key, then save |
| Upload succeeds but file not in bucket | Wrong region selected | Ensure the region in WPsigner matches the bucket’s actual region |
| Bucket appears empty in console | Path prefix is set | Navigate to the wpsigner/ folder inside the bucket |
| Large files fail | PHP memory limit too low | Increase memory_limit in php.ini (recommended: 256M+) |
Developer Hooks
Section titled “Developer Hooks”wps_s3_backup_key
Section titled “wps_s3_backup_key”Filter the S3 object key before upload. Use this to implement custom naming, folder structures, or routing logic.
add_filter('wps_s3_backup_key', function ($object_key, $document_id, $document, $provider_id) { // Only modify for Amazon S3, not Wasabi or R2 if ($provider_id !== 'amazon_s3') { return $object_key; }
// Organize by year/month $year = wp_date('Y'); $month = wp_date('m'); return "wpsigner/{$year}/{$month}/" . basename($object_key);}, 10, 4);Parameters:
| Parameter | Type | Description |
|---|---|---|
$object_key | string | Full S3 object key (e.g., wpsigner/Title_2026-03-06_42.pdf) |
$document_id | int | WPsigner document ID |
$document | object | Document object with title, status, and other properties |
$provider_id | string | Provider identifier (amazon_s3, wasabi, or cloudflare_r2) |
wps_s3_uploaded
Section titled “wps_s3_uploaded”Action fired after a successful upload.
add_action('wps_s3_uploaded', function ($document_id, $object_key, $provider_id) { if ($provider_id === 'amazon_s3') { error_log("Document {$document_id} backed up to S3: {$object_key}"); }}, 10, 3);Parameters:
| Parameter | Type | Description |
|---|---|---|
$document_id | int | WPsigner document ID |
$object_key | string | S3 object key where the file was uploaded |
$provider_id | string | Provider identifier |
Next Steps
Section titled “Next Steps”- Wasabi — S3-compatible, no egress fees
- Cloudflare R2 — Zero egress, global CDN
- Google Drive — OAuth-based backup
- Dropbox — Dropbox backup
- OneDrive — Microsoft OneDrive backup