Signing methods#
ATick for Node.js signs with a credential file or with an external key holder (USB token,
smart-card, HSM, OS certificate store, or a remote eSign service). Every signing call takes its
configuration as a single JSON options string, and every failure throws a normal Error.
const atick = require("atick");
const fs = require("fs");
Note
ATick for Node.js runs server-side. All inputs and outputs are Node Buffers, and the options
argument is a JSON string — build it with JSON.stringify({ ... }).
1. PFX / P12 / PEM file#
atick.signPfx is the primary method. It accepts both PKCS#12 (.pfx / .p12) and PEM —
the format is auto-detected.
const pdf = fs.readFileSync("in.pdf");
const pfx = fs.readFileSync("signer.pfx");
const signed = atick.signPfx(pdf, pfx, JSON.stringify({
password: "••••",
cn: "Aniket",
reason: "Approved",
pades: true,
}));
fs.writeFileSync("out.pdf", signed);
PEM credentials#
A PEM credential is an unencrypted PKCS#8 / PKCS#1 private key plus one or more CERTIFICATE
blocks. Pass its bytes as the pfx argument and use an empty password (""):
const pem = fs.readFileSync("signer.pem");
const signed = atick.signPfx(pdf, pem, JSON.stringify({
password: "",
cn: "Aniket",
pades: true,
}));
Note
Because the format is auto-detected, the same signPfx call works for .pfx, .p12, and .pem.
Only the password differs: the PKCS#12 passphrase for .pfx/.p12, and "" for PEM.
2. USB token / smart-card / HSM / OS store / eSign (deferred flow)#
ATick for Node.js does not load PKCS#11 libraries, the OS certificate store, or a remote eSign service itself. To sign with a key that never leaves a token, card, HSM, OS store, or eSign ESP, use the deferred flow: ATick prepares the document and hands you the exact bytes to sign, you produce the CMS signature with your own signer, and ATick embeds it.
// Step 1 — prepare. Returns { prepared, bytesToSign }.
const { prepared, bytesToSign } = atick.prepare(pdf, JSON.stringify({
cn: "Aniket",
reason: "Approved",
pades: true,
hash_algo: "sha256",
}));
// Step 2 — produce a CMS signature with your own signer.
// Sign `bytesToSign` using the token / smart-card / HSM / OS-store / eSign key.
// This is your own code (PKCS#11 binding, OS store, or a remote eSign ESP).
const cms = await signWithMySigner(bytesToSign); // returns a CMS/PKCS#7 SignedData Buffer
// Step 3 — embed the CMS into the prepared document.
const signed = atick.embed(prepared, cms);
fs.writeFileSync("out.pdf", signed);
Tip
The CMS you build in step 2 must cover bytesToSign exactly and use the same hash_algo you
passed to atick.prepare. This is the standard eSign / detached-signature pattern: ATick owns the
PDF structure, your signer owns the private key.
If you have the key material in software (a .pfx/.p12/.pem), ATick can also build the CMS for
you with atick.cmsPfx, then atick.embed:
const { prepared, bytesToSign } = atick.prepare(pdf, JSON.stringify({
cn: "Aniket",
pades: true,
}));
const cms = atick.cmsPfx(bytesToSign, pfx, JSON.stringify({
password: "••••",
pades: true,
}));
const signed = atick.embed(prepared, cms);
Common options#
All signing calls (signPfx, prepare / cmsPfx, signField) accept the same JSON keys.
Key |
Meaning |
|---|---|
|
PAdES ( |
|
|
|
add an RFC-3161 signature timestamp (B-T) |
|
choose / authenticate the timestamp authority |
|
embed long-term validation (B-LT) |
|
add a document timestamp (B-LTA) |
|
certification & locking |
|
pre-sign expiry / CRL / OCSP / chain checks |
|
the signature field name (auto-uniquified — |
|
one signature on many pages, or many fields sharing one value |
signPfx additionally accepts open_password (decrypt an encrypted input), and
encrypt_password / owner_password (password-protect the output).
Appearance options#
The visible signature block is also configured through the same JSON: cn, org, ou,
location, reason, text, date, dn, body, heading, show_mark, green_tick,
always_check, mark_color (hex "#E53935", name "blue", or [r, g, b]), mark_gradient,
mark_scale, text_color, bg_color, border, font_size, width, height, page,
rect ([x1, y1, x2, y2]), and placements ([[page, [x1, y1, x2, y2]], …]).
const signed = atick.signPfx(pdf, pfx, JSON.stringify({
password: "••••",
cn: "Aniket",
reason: "Approved",
show_mark: true,
green_tick: true,
mark_color: "#E53935",
page: 1,
rect: [36, 36, 236, 96],
pades: true,
}));
Multi-signatory (sign an already-signed PDF)#
ATick signs as an incremental update: existing signatures keep their byte ranges and stay valid. Just sign the already-signed PDF again — the field name is auto-uniquified so it never collides.
const v1 = atick.signPfx(pdf, pfx, JSON.stringify({
password: "••••",
cn: "Aniket",
pades: true,
})); // Atick_1
const v2 = atick.signPfx(v1, pfx, JSON.stringify({
password: "••••",
cn: "Reviewer",
pades: true,
})); // Atick_2
The same holds for the deferred flow: run atick.prepare -> external CMS -> atick.embed on the
already-signed bytes to add another signature.