common-gateway/waardepapieren-bundle
Installation
composer require common-gateway/waardepapieren-bundle
Add the bundle to config/bundles.php:
CommonGateway\WaardepapierenBundle\CommonGatewayWaardepapierenBundle::class => ['all' => true],
Configuration Publish the default config:
php bin/console config:dump-reference --env=prod | grep waardepapieren
Override settings in config/packages/common_gateway_waardepapieren.yaml:
waardepapieren:
issuer: "https://your-gov-domain.nl"
storage: "%kernel.project_dir%/var/waardepapieren"
jwt_secret: "%env(WAARDEPAPIEREN_JWT_SECRET)%"
First Use Case
Generate a Proof of Residency credential (e.g., BasisregistratiePersonen extract):
use CommonGateway\WaardepapierenBundle\Service\WaardepapierGenerator;
$generator = $this->container->get(WaardepapierGenerator::class);
$credential = $generator->generate(
subject: 'urn:uuid:123e4567-e89b-12d3-a456-426614174000',
type: 'ProofOfResidency',
claims: [
'bsn' => '123456789',
'address' => 'Main St 123, 2000 AA Haarlem',
'valid_from' => '2024-01-01',
'valid_until' => '2024-12-31'
]
);
Issuing Credentials
WaardepapierGenerator to create credentials on-the-fly (e.g., after user authentication).
$generator->generate($subject, $type, $claims, $options);
BatchCredentialIssuer:
$batchIssuer = new BatchCredentialIssuer($generator);
$batchIssuer->issueForUsers($userIds, 'ProofOfResidency');
Verification
return $this->json(['credential' => $credential->toJWT()]);
WaardepapierVerifier in controllers:
$verifier = $this->container->get(WaardepapierVerifier::class);
$isValid = $verifier->verify($jwtString, $expectedIssuer);
Integration with External Systems
# config/routes.yaml
waardepapieren_credential:
path: /api/credentials/{id}
controller: CommonGateway\WaardepapierenBundle\Controller\CredentialController::getCredential
// src/EventListener/CredentialRevokedListener.php
public function onRevoked(CredentialRevokedEvent $event) {
$this->mailer->send(new RevocationNotification($event->getSubject()));
}
Storage Backend
waardepapieren.storage).StorageInterface for databases or cloud storage:
class DatabaseStorage implements StorageInterface {
public function save(Credential $credential) { /* ... */ }
public function find(string $id) { /* ... */ }
}
JWT Secret Management
%env(WAARDEPAPIEREN_JWT_SECRET)%) and rotate secrets via:
php bin/console waardepapieren:rotate-secrets
Claim Validation
ClaimValidator or use Symfony’s validator:
# config/validator/constraints/Waardepapieren.yaml
CommonGateway\WaardepapierenBundle\Validator\Constraints\ValidBSN: ~
Revocation Latency
$message = new SyncRevocationListMessage();
$this->messageBus->dispatch($message);
Performance with Large Datasets
BatchCredentialIssuer:
$batchIssuer->setChunkSize(100); // Process 100 users at a time
Enable Verbose Logging
# config/packages/monolog.yaml
handlers:
waardepapieren:
type: stream
path: "%kernel.logs_dir%/waardepapieren.log"
level: debug
Test Locally with Mock Data
Use the WaardepapierGenerator with dummy claims to verify flows:
$generator->generate('urn:test', 'ProofOfResidency', ['bsn' => '999999999']);
Validate JWTs Manually Decode JWTs at jwt.io to debug payloads/headers:
php bin/console waardepapieren:decode-jwt "your.jwt.here"
Custom Credential Types
Extend AbstractCredential to add domain-specific logic:
class PropertyOwnershipCredential extends AbstractCredential {
public function getSubjectType(): string { return 'PropertyOwner'; }
protected function getDefaultClaims(): array {
return ['property_id' => 'urn:property:123', 'ownership_percentage' => 100];
}
}
Plugin Architecture Use Symfony’s event system to hook into the lifecycle:
// src/EventSubscriber/CredentialSubscriber.php
public static function getSubscribedEvents(): array {
return [
CredentialGeneratedEvent::class => 'onGenerated',
CredentialRevokedEvent::class => ['onRevoked', 100] // Low priority
];
}
UI Integration
CredentialController to add CRUD for manual issuance/revocation.How can I help you explore Laravel packages today?