bluescroll / human-attestation
Official SDK for HAP (Human Attestation Protocol) - cryptographic proof of verified human effort
Installs: 0
Dependents: 0
Suggesters: 0
Security: 0
Stars: 0
Watchers: 0
Forks: 0
Open Issues: 0
pkg:composer/bluescroll/human-attestation
Requires
- php: >=8.1
- guzzlehttp/guzzle: ^7.8
- web-token/jwt-signature: ^3.2
- web-token/jwt-signature-algorithm-eddsa: ^3.2
Requires (Dev)
- phpstan/phpstan: ^1.10
- phpunit/phpunit: ^10.4
README
Official HAP (Human Attestation Protocol) SDK for PHP.
HAP is an open standard for verified human effort. It enables Verification Authorities (VAs) to cryptographically attest that a sender took deliberate, costly action when communicating with a recipient.
Installation
composer require bluescroll/human-attestation
Requirements
- PHP 8.1+
- Sodium extension (built-in since PHP 7.2, but must be explicitly enabled in some environments)
Quick Start
Verifying a Claim (For Recipients)
<?php use BlueScroll\HumanAttestation\Verify; $verifier = new Verify(); // Verify a claim from a HAP ID $claim = $verifier->verifyClaim('hap_abc123xyz456', 'ballista.jobs'); if ($claim) { // Check if not expired if (Verify::isClaimExpired($claim)) { echo "Claim has expired\n"; return; } // Verify it's for your organization if (!Verify::isClaimForRecipient($claim, 'yourcompany.com')) { echo "Claim is for a different recipient\n"; return; } echo "Verified {$claim['method']} application to {$claim['to']['name']}\n"; }
Verifying from a URL
use BlueScroll\HumanAttestation\Verify; // Extract HAP ID from a verification URL $url = 'https://www.ballista.jobs/v/hap_abc123xyz456'; $hapId = Verify::extractIdFromUrl($url); if ($hapId) { $verifier = new Verify(); $claim = $verifier->verifyClaim($hapId, 'ballista.jobs'); // ... handle claim }
Verifying Signature Manually
use BlueScroll\HumanAttestation\Verify; $verifier = new Verify(); // Fetch the claim $response = $verifier->fetchClaim('hap_abc123xyz456', 'ballista.jobs'); if ($response['valid'] && isset($response['jws'])) { // Verify the cryptographic signature $result = $verifier->verifySignature($response['jws'], 'ballista.jobs'); if ($result['valid']) { echo "Signature verified! Claim: " . print_r($result['claim'], true); } else { echo "Signature invalid: " . $result['error']; } }
Signing Claims (For Verification Authorities)
<?php use BlueScroll\HumanAttestation\HumanAttestation; use BlueScroll\HumanAttestation\Sign; // Generate a key pair (do this once, store securely) $keys = Sign::generateKeyPair(); $privateKey = $keys['privateKey']; $publicKey = $keys['publicKey']; // Export public key for /.well-known/hap.json $jwk = Sign::exportPublicKeyJwk($publicKey, 'my_key_001'); $wellKnown = [ 'issuer' => 'my-va.com', 'keys' => [$jwk], ]; echo json_encode($wellKnown, JSON_PRETTY_PRINT) . "\n"; // Create and sign a claim $claim = Sign::createClaim( method: 'physical_mail', description: 'Priority mail packet with handwritten cover letter', recipientName: 'Acme Corp', issuer: 'my-va.com', domain: 'acme.com', expiresInDays: 730, // 2 years cost: ['amount' => 1500, 'currency' => 'USD'], time: 1800, physical: true ); $jws = Sign::signClaim($claim, $privateKey, 'my_key_001'); echo "Signed JWS: {$jws}\n";
API Reference
HumanAttestation Class (Static Utilities)
| Method | Description |
|---|---|
HumanAttestation::isValidId($id) |
Check if string matches HAP ID format |
HumanAttestation::generateId() |
Generate cryptographically secure HAP ID |
Verify Class
| Method | Description |
|---|---|
verifyClaim($hapId, $issuer) |
Fetch and verify a claim, returns claim or null |
fetchClaim($hapId, $issuer) |
Fetch raw verification response from VA |
verifySignature($jws, $issuer) |
Verify JWS signature against VA's public keys |
fetchPublicKeys($issuer) |
Fetch VA's public keys from well-known endpoint |
Verify::extractIdFromUrl($url) |
Extract HAP ID from verification URL |
Verify::isClaimExpired($claim) |
Check if claim has passed expiration |
Verify::isClaimForRecipient($claim, $domain) |
Check if claim targets specific recipient |
Sign Class
| Method | Description |
|---|---|
Sign::generateKeyPair() |
Generate Ed25519 key pair |
Sign::exportPublicKeyJwk($key, $kid) |
Export public key as JWK |
Sign::signClaim($claim, $privateKey, $kid) |
Sign a claim, returns JWS |
Sign::createClaim(...) |
Create claim with defaults |
License
Apache-2.0