Documentation · Capabilities

Automatic mode (remembered key)

So that the user doesn't have to pick the key file and type the password every single time, the key can be saved in the widget. From then on the operation runs without choosing a file or entering the container password — and with ttlMinutes, with no interaction at all.

Typical scenarios: signing 50 invoices in a row, working all day in an accountant's dashboard, bulk signing in an ERP.

The mode is available for the three widgets that work with a key:

Widget Behavior with a saved key
sign — signing silent, no modal (with ttlMinutes)
decrypt — decryption silent, no modal (with ttlMinutes)
auth — login with QES semi-automatic: no file or password needed, but the user always clicks “Sign in”

Why login with QES is not fully automated: confirming one's identity is the user's consent. We spare them the file and the password, but not the consent itself, so that a page cannot “log in” on their behalf without their knowledge.

First — enable the feature

Automatic mode is disabled by default: the widget behaves as usual (key and password every time), and the user sees no key-saving UI at all. It is enabled by the integrator — with an explicit parameter:

const signer = await embed('sign', { session: true });   //  ← enable key saving

//  the same for the other widgets that work with a key:
const dec  = await embed('decrypt', { session: true });
const auth = await embed('auth',    { session: true });
session value Behavior
not set feature disabled: key and password every time (the default)
true the key is saved; the PIN is asked for every time, the file and container password are not
{ ttlMinutes: 60 } don't ask for the PIN for 60 minutes within the tab — signing runs with no interaction
{ noPin: true } show the user a “Don't use a PIN” checkbox (by default there is none)

Step 1. Load the key in advance

A separate step, with no signing involved: a window opens with the key fields only; the user picks the file, enters the container password and makes up a short quick-access PIN code.

const signer = await embed('sign');

//  “Load key” — as a separate button in your interface
const st = await signer.session.setup();
// st = { saved: true, unlocked: true, needsPin: true, label: 'key.p12', … }

The key is stored in our origin (dstucrypt.com.ua) in encrypted form, as a separate record for your domain.

Step 2. From then on — no file, no password

//  the same call; what the user sees depends on the configuration:
const { signature } = await signer.sign(doc, { format: 'CAdES-T', digest: 'gost-34311' });
  • session: true (the default) — a compact window opens with a single PIN field. No file, no container password.
  • session: { ttlMinutes: N } — for the first N minutes after the PIN is entered, the modal does not open at all: signing runs silently. This is the mode for bulk operations (signing 50 invoices in a row).

ttlMinutes is a trade-off: the longer the interval, the more convenient it is for the user — and the wider the window in which a compromised page could sign something without their knowledge.

The key can also be saved “along the way”: the regular signing window has a “Remember the key on this site” checkbox with a PIN field. session.setup() is the same mechanism, just as a separate step, for when it's more convenient to set everything up in advance (for example, a “Connect key” button in the account settings).

Managing the session from your page

await signer.session.setup();                     //  load/replace the key

const st = await signer.session.status();
// { saved: true, unlocked: false, needsPin: true, label: 'key.p12', unlockedUntil: … }

if (st.saved && !st.unlocked) {
    await signer.session.unlock({ pin: userPin });   //  your own PIN screen in your UI
}

await signer.session.lock();     //  lock (the key stays saved)
await signer.session.forget();   //  remove the key from the browser entirely
status() field Meaning
saved a key is saved for this domain
unlocked the session is active — signing will run with no interaction
needsPin the key is protected by a PIN code (the default mode)
label the key file name (to show to the user)
unlockedUntil the time until which the session stays unlocked

If unlocked: false and you simply call sign() — the widget opens the modal and asks for the PIN. In other words, your working code doesn't break in any state.

Where and how the key is stored

  • The storage is our origin's localStorage. Your site has no access to it (Same-Origin Policy), and neither do other sites.
  • The record is bound to your domain. Our localStorage is shared by all sites that embed the widget, so each record is stored separately under the host's origin and is handed out to it only: a key saved on site-a.com is not accessible to site-b.com.
  • The storage holds ciphertext. The container and its password are packed into an AES-GCM-256 envelope; the encryption key is PBKDF2-SHA256 (310,000 iterations) derived from the PIN code. The PIN itself is never stored anywhere.
  • After the PIN is entered, the decrypted envelope lives only in the memory of the current widget instance — a new modal will ask for the PIN again. If ttlMinutes is set, it survives across modals within the tab (sessionStorage) and dies together with it.
  • The default key retention period is 30 days, after which the record deletes itself.

PIN-less mode — and why we advise against it

The option must first be allowed by the integrator (session: { noPin: true }) — only then does the “Don't use a PIN” checkbox appear in the widget. If the user checks it, signing runs immediately, with no input at all. The widget explicitly warns that this is less secure:

Without a PIN, the key in storage is protected only from other sites. Anyone with access to this computer and browser will be able to sign with it.

Technically, in this mode the envelope is encrypted with a random secret that sits right next to it in the same storage — this is obfuscation, not protection. Use it only on trusted workstations.

What to weigh up (honestly)

Automatic mode deliberately trades part of the security for convenience:

  • There is no confirmation of each signature. While the session is unlocked, your code can sign anything without the user's involvement. If your page gets compromised (XSS), the attacker will be able to sign documents on the user's behalf for as long as the session lasts. Without a saved key they would have to know the container password.
  • The key sits on the user's disk (encrypted). In the regular mode the key never leaves the tab's RAM at all.

Therefore:

  • the feature is disabled by default — enable it deliberately and only where it is really needed;
  • do not allow noPin without a weighty reason: the PIN is the main protection of the saved key;
  • keep ttlMinutes moderate (for example, the length of one working session);
  • for critical operations (payments, high-value contracts) keep the regular mode with confirmation;
  • give the user a “Forget key” button in your interface — signer.session.forget().