How digital acceptance works and how it is secured

Steps of the signing process, the methods, fingerprint and token handling, protections of the signing page, the evidence document, states, settings and endpoints.

The admin side of digital acceptance is the "Digital signature" card of the contract form (contract/esign.block); the signing page runs on the portal (contract/esign). Settings: contract/esign.settings (permission settings).

Flow

  1. Document: one of the PDFs linked to the contract (not the evidence). The kind comes from the document centre role, the signing mode from the source template; failing that, termination and completion certificate are one-sided, everything else two-sided.
  2. Signers: only the parties' persons, with the e-mail address resolved from the person (an address sent in the POST is not accepted). Two-sided: every required party gets a signer; one-sided: only the declaring party; unknown declarant: exactly one party.
  3. Method: click, email_otp (6-digit code by e-mail), sms_otp (not available, no live SMS path), dap (adapter ready, available = false). For employment contracts and the types marked in the settings only dap can be chosen.
  4. Freezing: the SHA-256 fingerprint of the PDF bytes (doc_sha256) is recorded when sending.
  5. Invitation: through the central mail path (esign_invite), on behalf of the client, in the signer's language; a unique link with a 64-hex-character token, validity 1–90 days (default 14).
  6. Signing page: expiry check; a different hash is refused (doc_changed); embedded PDF; declaration (signer, contract number, document name and SHA-256); required acceptance checkbox. E-mail code: valid 10 minutes, 5 attempts per code, at most 5 codes per signature, at least 60 s between codes. Decline with reason. Headers: noindex, no-store, no-referrer; POSTs with session token (CSRF).
  7. After signing: status signed, IP, browser, SHA-256 of the accepted declaration; evidence PDF into the document centre (signature_evidence): signer, e-mail, method, document and hash, times of sending, viewing and signing, IP, browser, declaration and hash, event log. Without a storage rule the signature remains valid, the gap is logged, and the evidence can be produced later (contract/esign.evidence).
  8. Summary: the contract's esign_status (empty, pending, partial, signed, declined) and esign_date; when every signer of the main contract document (role contract) has signed, date_signed receives the date of the last signature if empty.

Signature states: pending, sent, viewed, signed, declined, expired, cancelled. Resending uses a new token; withdrawal: cancel; expiry is lazy (on opening the link and loading the admin block).

Data model

Table names carry the installation's own prefix in the database. contract_signature (unique token_hash): contract_id, doc_id, doc_sha256, signer_person_id, signer_company_id, signer_name, signer_email, language_id, method, expires_at, otp_hash, otp_expires_at, otp_attempts, otp_sent_count, otp_sent_at, status, timestamps, decline_reason, ip, user_agent, accept_text_hash, evidence_doc_id. contract_signature_event: event, ip, user_agent, data (JSON, without secrets).

Security

The link token (256 bits) and the code are stored only as SHA-256 hashes (the code salted with the signature id); raw values never go into the event log, lists or logs. Event codes: created, sent, resent, viewed, reopened, otp_sent, otp_failed, signed, declined, expired, cancelled, doc_mismatch, mail_failed, evidence, evidence_failed.

Settings

Installation-specific JSON setting: types requiring a qualified signature (main or sub-type codes), default validity (days), DÁP: enabled, client id, certificate path, environment (test or prod), client secret (the interface only shows whether it is set).

Endpoints and permissions

EndpointPermission
contract/esign, .blocklist + scope
.sendsend + scope
.resend, .evidencesend
.cancelcancel
.settings, .savesettingssettings
portal: contract/esign, .document, .otp, .sign, .declinevalid, open link; POST + CSRF

E-mails: esign_invite, esign_otp. Log channel: contract/esign.