Logalty eSignature provider adapter for the Firefly Framework ECM abstraction — eIDAS-compliant electronic signatures (simple, advanced, qualified) with biometric, SMS-OTP and video signer identification.
- Overview
- Features
- Requirements
- Installation
- Quick Start
- Configuration
- How It Works
- Documentation
- Contributing
- License
This module is a pluggable eSignature provider adapter for the Firefly Framework Enterprise Content Management (ECM) abstraction. It implements the ECM signature SPI — SignatureEnvelopePort from fireflyframework-ecm — on top of Logalty, a Spanish qualified Trust Service Provider (TSP) whose certified electronic signature and digital evidence platform is compliant with the EU eIDAS regulation (Regulation (EU) No 910/2014).
ECM follows a hexagonal (ports-and-adapters) design: the core fireflyframework-ecm module defines provider-neutral ports for documents, content and signature envelopes, and each provider ships as a separate adapter module on the classpath. Applications program against the ECM ports; the concrete provider is selected at runtime by configuration. This adapter contributes the LogaltySignatureEnvelopeAdapter (annotated @EcmAdapter(type = "logalty"), mapped to SignatureProvider.LOGALTY) and wires it via Spring Boot auto-configuration.
The adapter is provider-selected: it activates only when firefly.ecm.esignature.provider=logalty is set. This makes Logalty a drop-in alternative to the sibling eSignature adapters — fireflyframework-ecm-esignature-docusign and fireflyframework-ecm-esignature-adobe-sign — without touching application code. The adapter is fully reactive (Spring WebFlux WebClient, Project Reactor) and hardened with Resilience4j circuit breaker and retry around every outbound Logalty API call, plus OAuth2 client_credentials token management with automatic refresh.
Maturity note: the current
LogaltySignatureEnvelopeAdapteris a reference/scaffold implementation. The OAuth flow, resilience pipeline, status mapping and the corecreateEnvelope/getEnvelope/sendEnvelope/getSigningUrl/archiveEnvelope/resendEnvelopepaths call the Logalty REST API, while some query operations (list-by-status, list-by-creator, expiring/completed lookups) and a few mutation paths (updateEnvelope,voidEnvelope) are placeholders to be completed against a live Logalty contract. Envelope-id mappings are held in-memory; replace with persistent storage for production.
- eIDAS-compliant electronic signatures — simple, advanced and qualified signature types via a configurable default (
default-signature-type). - Implements the ECM signature SPI — drop-in implementation of
SignatureEnvelopePort; declared as an@EcmAdapteradvertisingESIGNATURE_ENVELOPES,ESIGNATURE_REQUESTSandSIGNATURE_VALIDATIONcapabilities. - Provider-selected activation — switched on by
firefly.ecm.esignature.provider=logalty; coexists with other ECM eSignature adapters on the classpath without conflict. - Reactive, non-blocking — built on Spring WebFlux
WebClientand Project Reactor (Mono/Flux) end to end. - OAuth2 client-credentials auth — automatic access-token acquisition, caching and refresh with a configurable expiration window.
- Resilience built in — Resilience4j
CircuitBreaker(50% failure-rate threshold, sliding window of 10, automatic half-open transition) andRetry(configurable max attempts, exponential-friendly fixed wait) applied to all Logalty calls. - Strong signer identification — opt-in biometric signature capture, SMS-OTP verification and video identification.
- Embedded & remote signing — supports both remote email signing ceremonies and embedded signing with a configurable return URL.
- Long-term archival — Logalty document retention with a configurable retention period.
- Reminders — automatic signature reminders with a configurable frequency.
- Validated configuration —
@ConfigurationPropertieswith Jakarta Bean Validation constraints (required client credentials, bounded retries/timeouts/retention). - Spring Boot auto-configuration — zero hand-wiring; everything is contributed through
LogaltyAdapterAutoConfiguration.
- Java 21+ (Java 25 recommended)
- Spring Boot 3.x
- Maven 3.9+
fireflyframework-ecm(ECM core ports) on the classpath- A Logalty account with API credentials (client ID / client secret); production or sandbox endpoint
Add the adapter alongside the ECM core module. The version is managed by the Firefly parent/BOM, so you normally omit <version>:
<dependency>
<groupId>org.fireflyframework</groupId>
<artifactId>fireflyframework-ecm-esignature-logalty</artifactId>
<!-- version managed by the Firefly BOM / parent POM -->
</dependency>This module transitively brings in fireflyframework-ecm, but it is good practice to declare the core dependency explicitly:
<dependencies>
<dependency>
<groupId>org.fireflyframework</groupId>
<artifactId>fireflyframework-ecm</artifactId>
</dependency>
<dependency>
<groupId>org.fireflyframework</groupId>
<artifactId>fireflyframework-ecm-esignature-logalty</artifactId>
</dependency>
</dependencies>With the dependency on the classpath, activate the adapter by selecting Logalty as the eSignature provider and supplying credentials:
firefly:
ecm:
esignature:
provider: logalty # selects this adapter (required to activate)
adapter:
logalty:
client-id: ${LOGALTY_CLIENT_ID}
client-secret: ${LOGALTY_CLIENT_SECRET}
base-url: https://api.logalty.comThat is all the wiring required. LogaltyAdapterAutoConfiguration contributes the WebClient, CircuitBreaker, Retry, ObjectMapper and the LogaltySignatureEnvelopeAdapter bean automatically.
Inject the provider-neutral SignatureEnvelopePort — your code never references Logalty directly:
import org.fireflyframework.ecm.domain.model.esignature.SignatureEnvelope;
import org.fireflyframework.ecm.port.esignature.SignatureEnvelopePort;
import org.springframework.stereotype.Service;
import reactor.core.publisher.Mono;
import java.util.UUID;
@Service
public class ContractSigningService {
private final SignatureEnvelopePort envelopes; // backed by Logalty at runtime
public ContractSigningService(SignatureEnvelopePort envelopes) {
this.envelopes = envelopes;
}
public Mono<SignatureEnvelope> startContract(SignatureEnvelope draft, UUID sender) {
return envelopes.createEnvelope(draft)
.flatMap(created -> envelopes.sendEnvelope(created.getId(), sender));
}
public Mono<String> signingLink(UUID envelopeId, String email, String name) {
return envelopes.getSigningUrl(envelopeId, email, name, null);
}
}Switching providers later is a configuration change only: swap the dependency and set firefly.ecm.esignature.provider to docusign or adobe-sign.
All properties live under the firefly.ecm.adapter.logalty prefix (bound by LogaltyAdapterProperties). The adapter only activates when firefly.ecm.esignature.provider=logalty.
firefly:
ecm:
esignature:
provider: logalty # activation switch (no default)
adapter:
logalty:
# --- Authentication (client credentials required) ---
client-id: ${LOGALTY_CLIENT_ID} # required
client-secret: ${LOGALTY_CLIENT_SECRET} # required
username: # optional, alternative to OAuth
password: # optional, alternative to OAuth
# --- Endpoint ---
base-url: https://api.logalty.com # production; sandbox: https://api-sandbox.logalty.com
api-version: v1
sandbox-mode: false
# --- Webhooks ---
webhook-url: # receive signature status callbacks
webhook-secret: # validate incoming webhook requests
# --- HTTP / resilience ---
connection-timeout: 30s # Duration
read-timeout: 60s # Duration
max-retries: 3 # 0..10
token-expiration: 3600 # seconds, 300..86400
# --- Signing behaviour ---
default-signature-type: ADVANCED # SIMPLE | ADVANCED | QUALIFIED
enable-embedded-signing: false
return-url: # used for embedded signing
enable-biometric-signature: false
enable-sms-verification: false
enable-video-identification: false
# --- Messaging ---
default-email-subject: "Firma requerida / Signature required"
default-email-message: "Por favor, revise y firme el documento adjunto / Please review and sign the attached document."
# --- Reminders & retention ---
enable-reminders: true
reminder-frequency-days: 3 # 1..30
enable-document-retention: true
document-retention-days: 365 # 1..3650| Property | Default | Description |
|---|---|---|
firefly.ecm.esignature.provider |
(none) | Must equal logalty to activate this adapter. |
client-id |
(required) | Logalty API client ID used for OAuth2 client_credentials. |
client-secret |
(required) | Logalty API client secret. |
base-url |
https://api.logalty.com |
Logalty API endpoint; use the sandbox host for testing. |
api-version |
v1 |
API version segment used when building request URIs. |
default-signature-type |
ADVANCED |
eIDAS signature level: SIMPLE, ADVANCED or QUALIFIED. |
connection-timeout / read-timeout |
30s / 60s |
HTTP connection and response timeouts. |
max-retries |
3 |
Retry attempts for transient failures (0–10). |
token-expiration |
3600 |
OAuth token lifetime in seconds (300–86400). |
enable-biometric-signature |
false |
Capture biometric signature data. |
enable-sms-verification |
false |
Require SMS-OTP signer verification. |
enable-video-identification |
false |
Require video identification of signers. |
enable-embedded-signing / return-url |
false / (none) |
Enable in-app embedded signing and the post-signature redirect URL. |
enable-document-retention / document-retention-days |
true / 365 |
Long-term archival in Logalty (1–3650 days). |
enable-reminders / reminder-frequency-days |
true / 3 |
Automatic signature reminders (1–30 days). |
webhook-url / webhook-secret |
(none) | Endpoint and shared secret for inbound status callbacks. |
client-id and client-secret are validated as @NotBlank; the bounded numeric properties are enforced via @Min/@Max. Invalid configuration fails fast at startup.
LogaltyAdapterAutoConfiguration is registered through META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports and is gated by @ConditionalOnClass({WebClient.class, CircuitBreaker.class}) and @ConditionalOnProperty(firefly.ecm.esignature.provider=logalty). When active it contributes (each as @ConditionalOnMissingBean, so any can be overridden):
- a reactive
WebClientbound tobase-urlwith the configured response timeout; - a named
logaltyCircuitBreaker(CircuitBreaker) — 50% failure-rate threshold, 30s open state, sliding window of 10, automatic open→half-open transition; - a named
logaltyRetry(Retry) —max-retriesattempts retrying socket/IO/WebClientRequestExceptionfailures; - a Logalty-tuned
ObjectMapper; and - the
LogaltySignatureEnvelopeAdapter(SignatureEnvelopePort) wired with the ECMDocumentPortandDocumentContentPort.
Every outbound call goes through ensureValidAccessToken() (cached OAuth2 token with a 60-second safety margin) and is decorated with the circuit breaker and retry operators (transformDeferred(CircuitBreakerOperator.of(...)) / RetryOperator.of(...)). Logalty status values are normalised to the ECM EnvelopeStatus enum (DRAFT, SENT, COMPLETED, VOIDED, EXPIRED).
- Firefly Framework organization and module catalog: github.com/fireflyframework
- ECM core ports (the SPI this adapter implements): fireflyframework-ecm
- Sibling eSignature adapters: DocuSign · Adobe Sign
- Logalty platform: logalty.com
Contributions are welcome. Please read the CONTRIBUTING.md guide for details on our code of conduct, development process, and how to submit pull requests.
Copyright 2024-2026 Firefly Software Foundation.
Licensed under the Apache License, Version 2.0. See LICENSE for details.