nexxai / laravel-rfc3161
A Laravel package for creating RFC 3161 compliant timestamps
Fund package maintenance!
Requires
- php: ^8.3
- illuminate/contracts: ^11.0||^12.0||^13.0
- illuminate/database: ^11.0||^12.0||^13.0
- illuminate/http: ^11.0||^12.0||^13.0
- illuminate/support: ^11.0||^12.0||^13.0
- spatie/laravel-package-tools: ^1.16
- symfony/process: ^7.2
Requires (Dev)
- larastan/larastan: ^3.0
- laravel/pint: ^1.14
- nunomaduro/collision: ^8.8
- orchestra/testbench: ^9.0.0||^10.0.0||^11.0.0
- pestphp/pest: ^4.0
- pestphp/pest-plugin-arch: ^4.0
- pestphp/pest-plugin-laravel: ^4.1
- phpstan/extension-installer: ^1.4
- phpstan/phpstan-deprecation-rules: ^2.0
- phpstan/phpstan-phpunit: ^2.0
README
nexxai/laravel-rfc3161 is a thin Laravel interface for RFC 3161 timestamp providers. It creates timestamp requests, sends them to your selected provider, stores the request/response binary payloads, and verifies responses with provider-specific certificates.
Breaking Changes
- The package namespace changed from
Nexxai\\FreeTsa\\...toNexxai\\Rfc3161\\.... - Update all imports, config class references, and type hints to the new namespace.
Installation
Requirements
- PHP must be able to execute an
opensslCLI binary for RFC 3161 verification. - By default this package calls
opensslfrom yourPATH; setTIMESTAMP_OPENSSL_BINARYif your binary lives elsewhere.
You can install the package via composer:
composer require nexxai/laravel-rfc3161
You can publish and run the migrations with:
php artisan vendor:publish --tag="rfc3161-migrations"
php artisan migrate
Add the package trait to your model so it gets the timestampRecords() polymorphic relationship:
use Nexxai\Rfc3161\Concerns\HasRfc3161Timestamps; class User extends Authenticatable { use HasRfc3161Timestamps; }
You can publish the config file with:
php artisan vendor:publish --tag="rfc3161-config"
This is the contents of the published config file:
return [ 'default_provider' => env('TIMESTAMP_PROVIDER', \Nexxai\Rfc3161\Providers\FreeTsa::class), 'hash_algorithm' => env('TIMESTAMP_HASH_ALGORITHM', 'sha512'), 'openssl_binary' => env('TIMESTAMP_OPENSSL_BINARY', 'openssl'), 'validate_certificate_chain' => env('TIMESTAMP_VALIDATE_CERTIFICATE_CHAIN', true), 'certificates' => [ 'directory' => env('TIMESTAMP_CERTIFICATES_DIRECTORY', storage_path('app/timestamp/certificates')), ], ];
Provider endpoints and certificate chains are built into provider classes and are not user-configurable.
Set TIMESTAMP_PROVIDER to a provider class (for example Nexxai\\Rfc3161\\Providers\\DigiCert) to choose the default provider.
When overriding the provider in code, pass a provider object (for example new DigiCert()).
Before timestamp verification, download and store trusted certificates for your provider:
php artisan timestamp:download-certificates
If certificates are missing, verification will throw an exception with this command.
The package requests certificate inclusion in each TSQ (-cert) and, during verification, prefers the certificate chain embedded in the TSR for per-response validation. Local provider certificates are used as trust anchors (-CAfile) and as a fallback untrusted chain when a TSR does not include certificates.
When TIMESTAMP_VALIDATE_CERTIFICATE_CHAIN=true, the package validates trusted local certificates before requests and verification. If validation fails, it attempts one fresh re-download for that provider and throws an exception if validation still fails.
Usage
timestampFile() is a method on the Eloquent model (Nexxai\Rfc3161\Models\Timestamp), not the facade (Nexxai\Rfc3161\Facades\Timestamp).
If you need both in the same file, alias them so calls stay explicit:
use Nexxai\Rfc3161\Models\Timestamp as TimestampRecord; use Nexxai\Rfc3161\Facades\Timestamp as TimestampFacade; $timestamp = TimestampRecord::timestampFile($filePath, $invoice); $rawResponse = TimestampFacade::requestTimestamp($filePath);
use App\Models\Invoice; use Nexxai\Rfc3161\Models\Timestamp; use Nexxai\Rfc3161\Providers\DigiCert; $invoice = Invoice::findOrFail(1); // Creates a TSQ from file content, sends it to your configured default provider, and stores TSQ/TSR binary payloads. $timestamp = Timestamp::timestampFile( storage_path('app/invoices/invoice-2026-04.pdf'), $invoice, ); // You can choose a specific provider per request. $timestamp = Timestamp::timestampFile( storage_path('app/invoices/invoice-2026-04.pdf'), $invoice, new DigiCert(), ); // Verify stored query and response with locally downloaded provider certificates. $isValid = $timestamp->verify(); // You can also verify explicit query/response data. $isValid = $timestamp->verify($customTsqBinary, $customTsrBinary);
The timestamps table includes a nullable polymorphic relation (timestampable_type, timestampable_id) so any Eloquent model can own many timestamp records.
After adding the trait, access records with $user->timestampRecords (or call $user->timestampRecords() for the relation query).
Testing
composer test
Releases
This package uses Release Please to create and publish semver releases from main.
Use Conventional Commits in merged PRs so the version bump is predictable:
fix: ...-> patch release (x.y.Z)feat: ...-> minor release (x.Y.0)feat!: ...or aBREAKING CHANGE:footer -> major release (X.0.0)
Example:
feat: add certificate download command
fix: handle missing cert files before verify
feat!: rename timestampFile API to createFromFile
Changelog
Please see CHANGELOG for more information on what has changed recently.
Security Vulnerabilities
Please review our security policy on how to report security vulnerabilities.
Credits
License
The MIT License (MIT). Please see License File for more information.