All work

Platforms & Products

SignFlow: The E-Signature Service

Renting your compliance story from a signature vendor means the evidence lives in their account, under their breach policy, on their retention schedule.

Designed and builtHonoTypeScriptpdf-lib / @signpdfPAdESSQLiteSHA-256
  • A signature is an evidentiary claim needing four things: consent, intent, attribution, and the exact document version.
  • No third party holds the evidence, so it is not on somebody else's retention schedule or breach policy.
  • Every event is hash-chained, so altering history means rewriting all of it, and that is visible.

The problem

An electronic signature is not a picture of a name. Under ESIGN and UETA it is an evidentiary claim, and it needs four things: consent to do business electronically, intent to sign, attribution to an authenticated identity, and the exact version of the document that was agreed to.

Every one of those is a fact you have to be able to prove later, to somebody hostile, possibly years later. Which means the interesting engineering is not applying the signature. It is the record.

Its own service, on purpose

SignFlow is a separate repository and a separate hardened service rather than a module inside the portals. That is a security boundary, deliberately drawn: the code that touches signature material and PDF internals does not share an attack surface with a public web UI that accepts uploads from strangers.

PDF parsing is a notoriously rich source of memory bugs. Putting it behind its own door, with its own blast radius, is cheap now and very expensive to retrofit later.

An audit trail that cannot be quietly edited

Every event in an envelope's life is appended to a log where each entry's hash is computed over the previous entry's hash plus its own canonical content. Change one timestamp two years later and every hash after it stops matching. You cannot alter history without rewriting all of it, and rewriting all of it is visible.

This is the difference between an audit log and a table of rows that somebody with database access could have written this morning:

const canonical = JSON.stringify(entry, Object.keys(entry).sort());
const hash = sha256Hex((prevHash ?? "") + canonical);

// the resulting chain, per envelope:
  1  sent       prev: null      hash: 9f2a...
  2  viewed     prev: 9f2a...   hash: c17b...
  3  consented  prev: c17b...   hash: 40de...
  4  signed     prev: 40de...   hash: aa91...
  5  completed  prev: aa91...   hash: 7c35...

// edit event 2 and events 3, 4 and 5 no longer verify.
The chaining rule, and what it produces. The content is canonicalised with sorted keys before hashing, so two records with the same facts hash identically regardless of field order. Each hash covers the one before it, which is what makes the trail evidence rather than a list.

The seal on the document itself

The signed PDF carries a PAdES style signature: a SHA-256 digest over a declared byte range of the file. Verification re-reads that byte range and re-computes the digest, so any edit made after signing, one character in one field, fails the check.

The trail and the artifact are two independent proofs. The chain shows what happened and when. The seal shows the document nobody has touched since.

And a certificate that says all of it out loud

Every completed envelope emits a Certificate of Completion: signer identity, address of record, timestamps, the document hash, and every event in order. It is the artifact you hand to whoever is asking, and it exists because the moment you need it is never the moment you want to start assembling it.

Engineering decisions

The calls I made, and what each one cost.

Build it rather than rent it.

Renting means the evidence for your compliance story lives in a third party's account, under their retention schedule and their breach policy. For tax and health documents that is a dependency I was not willing to carry, and it is a per envelope cost forever.

Its own repository, its own service, its own hardening.

PDF and PKI code is exactly the kind of parsing surface that produces memory bugs. It does not belong in the same process as the public web UI.

Hash chain the events instead of trusting the database.

Anyone who can write the audit table can also write a convincing lie into it. A chain makes the lie require rewriting everything after it, and that is detectable by anyone holding an earlier copy.

More systems

I'm looking for Incident Commander and SRE roles.

If your team is drowning in toil, alert noise, or incidents that never quite close. That is the work I do.

Get in touch