Appearance
AutoFirma Module for Laravel/Filament
Index
- Introduction
- Requirements
- Installation
- Configuration
- Basic Usage
- Components
- API
- Customization
- Troubleshooting
- FAQ
Introduction
The AutoFirma module provides full integration with the Spanish Government's AutoFirma digital signature client for Laravel applications using Filament. It allows users to digitally sign PDF documents using their digital certificates.
Key Features
✅ Digital signing of PDF documents (PAdES format)
✅ Support for Spanish certificates (DNIe, FNMT, etc.)
✅ Digital signature validation
✅ Download signed documents
✅ Full signature audit trail
✅ Integrated interface with Filament v3
✅ Multi-language support (ES/EN)
Requirements
Server Requirements
- PHP 8.3 or higher
- Laravel 11.x or higher
- Filament 3.x
- PHP Extensions:
- ext-openssl
- ext-json
- fileinfo
Client Requirements
- AutoFirma installed on the user's computer (firmaelectronica.gob.es)
- Valid digital certificate (DNIe, FNMT-RCM, etc.)
- Supported browsers:
- Chrome/Edge (recommended)
- Firefox
- Safari 11+
- Brave
Installation
1. Install dependencies
bash
composer require phpseclib/phpseclib:^3.0
- Install the module:
bash
composer require e2tmk/autofirma-module
or
bash
php artisan mm:require-module autofirma
- Publish assets and config:
bash
php artisan vendor:publish --tag=autofirma-config
php artisan vendor:publish --tag=autofirma-assets
php artisan vendor:publish --tag=autofirma-translations
- Run migrations:
bash
php artisan migrate
- Register the plugin in Filament (Optional):
php
use Modules\AutoFirma\Filament\Plugin\AutoFirmaPlugin;
public function panel(Panel $panel): Panel
{
return $panel
->plugins([
AutoFirmaPlugin::make(),
]);
}
Configuration
Config File
config/autofirma.php
:
php
return [
'enabled' => env('AUTOFIRMA_ENABLED', true),
'formats' => [
'pdf' => 'PAdES',
'xml' => 'XAdES',
'default' => 'CAdES',
],
'storage' => [
'disk' => env('AUTOFIRMA_STORAGE_DISK', 'local'),
'signed_documents_path' => 'autofirma/signed',
'max_file_size' => 50 * 1024 * 1024,
],
'validation' => [
'check_revocation' => env('AUTOFIRMA_CHECK_REVOCATION', false),
'trusted_cas' => [
'AC FNMT Usuarios',
'AC Administración Pública',
],
],
];
Environment Variables
env
AUTOFIRMA_ENABLED=true
AUTOFIRMA_STORAGE_DISK=local
AUTOFIRMA_CHECK_REVOCATION=false
Basic Usage
1. Add actions to table
php
use Modules\AutoFirma\Filament\Actions\SignPdfAction;
use Modules\AutoFirma\Filament\Actions\ValidateSignatureAction;
use Modules\AutoFirma\Filament\Actions\DownloadSignedAction;
public function table(Table $table): Table
{
return $table
->columns([
// your columns
])
->actions([
SignPdfAction::make()
->documentField('file_path')
->documentType('Document') // Model
->signatureFormat('PAdES'),
ValidateSignatureAction::make()
->documentType('Document'), // Model
DownloadSignedAction::make()
->documentType('Document'), // Model
]);
}
2. Make model signable
Migration:
php
Schema::table('documents', function (Blueprint $table) {
$table->string('status')->default('draft');
$table->string('signed_file_path')->nullable();
$table->timestamp('signed_at')->nullable();
$table->unsignedBigInteger('signed_by')->nullable();
$table->json('signature_metadata')->nullable();
});
Model:
php
class Document extends Model
{
protected $fillable = [
'title', 'file_path', 'status',
'signed_file_path', 'signed_at',
'signed_by', 'signature_metadata',
];
protected function casts(): array {
return [
'signed_at' => 'datetime',
'signature_metadata' => 'array',
];
}
public function markAsSigned(array $signatureData = []): bool
{
return $this->update([
'status' => 'signed',
'signed_at' => now(),
'signed_by' => auth()->id(),
'signature_metadata' => $signatureData,
'signed_file_path' => $signatureData['signed_document_path'] ?? null,
]);
}
}
Components
SignPdfAction
php
SignPdfAction::make()
->documentField('file')
->documentType('Document') // Model
->signatureFormat('PAdES')
->modalHeading('Sign Document')
->modalDescription('Use your digital certificate')
//TODO - available in future updates
->extraParams([
...
'signatureVisible' => 'true',
'signaturePage' => '1',
'layer2Text' => 'Digitally signed',
...
]);
ValidateSignatureAction
php
ValidateSignatureAction::make()
->documentType('Document') // Model
->label('Verify')
->icon('heroicon-o-shield-check');
DownloadSignedAction
php
DownloadSignedAction::make()
->documentType('Document') // Model
->downloadOriginalIfNotSigned(true);
API
POST /api/autofirma/signatures
json
{
"document_id": "1",
"document_type": "Document", // Model
"signature": "base64_of_signed_pdf",
"certificate": "base64_of_certificate",
"metadata": {
"filename": "contract.pdf"
}
}
Response
json
{
"success": true,
"message": "Digital signature saved successfully",
"data": {
"id": 123,
"signed_at": "2025-01-26T10:30:00Z",
"signer_name": "John Smith",
"signer_nif": "12345678A",
"format": "PAdES"
}
}
Other endpoints
GET /api/autofirma/signatures?document_id=123&document_type=Contract
GET /api/autofirma/signatures/{id}/download
GET /api/autofirma/signatures/{id}/verify
JavaScript API
js
const autoFirma = new AutoFirmaWrapper({
timeout: 60000,
formats: {
pdf: 'PAdES',
xml: 'XAdES',
default: 'CAdES'
}
});
const result = await autoFirma.signDocument(documentBase64, {
format: 'PAdES',
algorithm: 'SHA256withRSA'
});
const isAvailable = await autoFirma.checkAvailability();
Backend Service
php
use Modules\AutoFirma\Services\AutoFirmaService;
public function __construct(
private AutoFirmaService $autoFirmaService
) {}
$signature = $this->autoFirmaService->processSignature(
documentId: '1',
documentType: 'Document', // Model
signatureBase64: $signatureData,
certificateBase64: $certificateData,
metadata: ['user_id' => auth()->id()]
);
Customization
Visible signature
js
buildSignatureParams(config) {
const params = {};
if (config.format === 'PAdES') {
'signatureVisible' => 'true',
'signaturePage' => '1',
'signaturePositionOnPageLowerLeftX' => '50',
'signaturePositionOnPageLowerLeftY' => '50',
'signaturePositionOnPageUpperRightX' => '200',
'signaturePositionOnPageUpperRightY' => '100',
'layer2Text' => 'Signed by: $$SUBJECTCN$$\nDate: $$SIGNDATE=dd/MM/yyyy$$',
'layer2FontFamily' => '2',
'layer2FontSize' => '12',
'layer2FontColor' => 'black',
}
if (config.extraParams) {
Object.assign(params, config.extraParams);
}
return this.serializeParams(params);
}
Add logo to signature
js
'signatureRubricImage' => base64_encode(file_get_contents('logo.png')),
Custom translations
bash
cp vendor/e2tmk/autofirma/resources/lang/es/autofirma.php \
resources/lang/vendor/autofirma/es/autofirma.php
Troubleshooting
Check installation
bash
Windows: C:\Program Files\AutoFirma\AutoFirma.exe
macOS: /Applications/AutoFirma.app
Linux: /usr/bin/AutoFirma
Service not responding
Check WebSocket ports: 63117
, 64917
, 55437
Error: "Failed to store digital signature"
php
ini_set('post_max_size', '50M');
ini_set('upload_max_filesize', '50M');
ini_set('memory_limit', '512M');
bash
chmod -R 775 storage/app/autofirma
Error: "Malformed UTF-8 characters"
php
return response()->streamDownload(
function () use ($content) {
echo $content;
},
'signed_document.pdf',
['Content-Type' => 'application/pdf']
);
Signature not visible
js
...
'signatureVisible' => 'true',
'signaturePage' => '1',
'layer2Text' => 'Digitally signed',
...
Error: "AutoFirma not found"
bash
Windows: Check in Programs and Features
macOS: Check in Applications
Linux: Run `which autofirma`
Browser issues
- Avoid incognito mode
- Clear cache
- Check if browser allows
afirma://
protocol
Error: Too many function arguments
bash
ls -la public/vendor/autofirma/js/autoscript.js
wc -l public/vendor/autofirma/js/autoscript.js
CORS
php
// Good
$url = '/storage/' . $document;
// Bad
$url = 'http://domain.com/storage/' . $document;
Security Considerations
- Always use HTTPS
- Validate certificates server-side
- Restrict access to signature endpoints
- Store signatures securely (consider encryption)
- Implement rate limiting
Certificate Validation
- Expiry date
- Revocation status (OCSP/CRL)
- Trusted CA
- Signature integrity
Audit Trail
php
$signature = Signature::find($id);
$audits = $signature->audits;
foreach ($audits as $audit) {
echo $audit->action . ' by user ' . $audit->user_id;
}
FAQ
What certificates are supported?
- Spanish DNIe
- FNMT
- ACCV
- Camerfirma
- Any certificate recognized by the Spanish Administration or Eusko Jaularitza (Basque Administration)
Can I sign formats other than PDF?
Yes: PAdES, XAdES, CAdES
How do I verify a signed document?
- Use
ValidateSignatureAction
- Open in Adobe Reader
- Use the VALIDe government platform
Is AutoFirma always required to be running?
Only when signing. Not needed for viewing/downloading signed docs.
Where are signed documents stored?
php
'storage' => [
'disk' => 'public',
'signed_documents_path' => 'documents/signed',
],
Support
AutoFirma Installation
Download from:
https://firmaelectronica.gob.es/Home/Descargas.html