Skip to content

Document the signing service - #16

Open
maricavor wants to merge 12 commits into
mainfrom
add-signing
Open

maricavor wants to merge 12 commits into
mainfrom
add-signing

Conversation

@maricavor

Copy link
Copy Markdown
Contributor

No description provided.

A new top-level section covering both ways in: the hosted page, where eeID shows
the document and walks the signer through their method, and the headless
endpoints for an integrator with their own interface -- including hash-only
ingest, where eeID is given digests and never receives the document.

Written around the things an integrator gets wrong rather than an endpoint list.
Sign the digest of the SignedInfo, never the document, or the signature verifies
against nothing inside a container that looks plausible. Verify the postback
before acting on it, and note that its signature covers a timestamp, unlike the
identification webhook's -- the two verifications are not interchangeable. Do not
rely on the redirect to tell you anything, because the signer may have closed the
tab or opened the link on a different device. Keep the signing_uuid and not the
session token, which is the signer's capability for the signed document.

The hash-only merge rules are spelled out, mimetype entry included: that one
produces a container some validators accept and the DigiDoc4 client refuses, which
is a bug you find only when someone cannot open your document.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01GP9ZnyKyjjFfBmv3evRGV3
@github-actions

Copy link
Copy Markdown

Docs Preview

Preview deployed successfully.

Access it here: https://internetee.github.io/eeID-DOC/previews/pr-16/

deploy.sh and others added 11 commits September 17, 2026 12:28
The container endpoint serves it now, so an integrator using eeID's hosted page
with hash-only ingest can collect the signature they produced. Previously the
merge instructions only applied to the headless path, because that was the only
place the hashcode container was ever handed over.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01GP9ZnyKyjjFfBmv3evRGV3
signing_method is gone from create. Which methods and countries a service signs
with is configured on the service and chosen by the signer, exactly as for
authentication and from the same auth_methods -- so the two cannot drift, and an
integrator is not overriding a decision that was never theirs.

It survives on /prepare alone, where there is no signer page and nobody else can
say which method signed. There it need not be a method eeID has built a flow for:
the integrator drives the device, so the ID card works on that path today.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01GP9ZnyKyjjFfBmv3evRGV3
Smart-ID+ is a separate method, not a variant: in eeID it is the device-link
flow, and signing drives the notification API. A service may be configured for
it, and the headless endpoints accept it, but the hosted page does not offer it.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01GP9ZnyKyjjFfBmv3evRGV3
Six endpoints and a webhook, one line each, linked into the narrative. The
section explains the flow well and reads badly as a lookup -- an integrator
checking one parameter had 390 lines to scroll.

It also states the two things the table cannot: that there is no signing_method
parameter, because the service and the signer decide, and that sign_url is not
part of this API. Both are questions an integrator arrives with.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01GP9ZnyKyjjFfBmv3evRGV3
`container` in place of `documents` on create. The documents come out of the
container rather than being sent again, the signatures already on it are kept,
and what comes back has one more.

Says what integrators need and cannot guess: ingest_mode tells them whether eeID
assembled the result or they merge it, rounds cannot overlap because each one
rewrites the container, and each round is its own signing_uuid because eeID does
not relate them.

The warning is specific about where the guard reaches. eeID refuses a signed
container sent in `documents` when it can see the bytes; in hash-only ingest it
cannot, because only digests arrive and nothing about them says "container".

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01GP9ZnyKyjjFfBmv3evRGV3
The text said an erasure that left the container "would be no erasure at all",
which reads as a guarantee. It is not one: when several signatures share a
container, eeID keeps it and reports that it did, because the signer's identity
code is inside their signature and that signature is in the same file as
everyone else's -- which is also the only proof those others signed.

No service can reach that today: several signatures on one document is off
unless a service is permitted them, and none is. But the sentence is already
written and already absolute, and it is the kind a DPO relies on or a DPA
quotes. A doc that is silent about a capability is fine; one that promises an
erasure guarantee is not.

So the claim is now conditional and the response is shown, because it gained an
`erasure` object that every caller receives. `signer_id_code` -- which erases one
person rather than the document -- is deliberately still undocumented: it wants
writing up when the first service is permitted several signatures, together with
what `complete: false` obliges the caller to do.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01GP9ZnyKyjjFfBmv3evRGV3
It sat in the countersigning section, which reads oddly: that section opens by
telling you to send `container` instead of `documents`, and the warning
immediately restated it as "do not send a container in documents" -- the same
instruction twice in opposite moods, addressed to a reader already doing it
right.

The person who needs it is reading the documents section, about to upload an
.asice as a file. So it moves there, leads with what the thing is rather than
with the limits of eeID's guard -- "do not rely on eeID to stop you" told the
reader eeID was unreliable before telling them what the mistake was -- and
points at `container` instead of describing it again.

Shorter too: the mechanism needed one sentence, not four.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01GP9ZnyKyjjFfBmv3evRGV3
Read end to end against the code rather than as the sum of the edits that built
it, which is how the drift got in. Six corrections.

Smart-ID+ was described as configurable for signing and offered "as their flows
are built". It cannot be configured at all: it is deliberately absent from
Signing::SIGNING_METHODS, so a service's signing methods can never contain it.
The chapter now says it is not a signing method, in both places it came up.

Several signatures on one document was documented as simply available. It is off
unless a service asks for it and answers 403 otherwise -- which appeared neither
in "Enabling signing", nor in the countersigning section, nor in the error
table. All three now say so, with the reason: a signer's identity code shares a
container with everyone else's, so one person's erasure cannot be fully honoured
without destroying the other signers' proof.

The container window was 180 days in two places and is 30.

Document retention was stated unconditionally as "purged immediately". On a
service permitted several signatures the bytes stay until the container is
purged, because a further round needs them.

`signatures` on the status response was undocumented, including that a `pending`
entry beside a `signed` status is a waiting round rather than a contradiction --
a document is signed once anybody has signed it.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01GP9ZnyKyjjFfBmv3evRGV3
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01GP9ZnyKyjjFfBmv3evRGV3
Four things eeID answers that the chapter did not mention.

`locale` sets the language the signing page opens in, the counterpart of
ui_locales on an authentication request -- which is accepted as an alias, so an
integrator already sending one OIDC-shaped parameter does not have to learn that
this endpoint spells it differently.

`signing_uuid` starts a new round on a signing eeID already holds. It is what to
use once a signer's link is spent: re-uploading the same bytes makes a second
signing record of the same document and a second thing to reconcile.

`signing_failed` is no longer the last word. A round that failed technically can
be tried again on the same link, and `signing_completed` then follows and
supersedes it -- so postbacks have to be handled last-wins rather than treating
the first failure as final. A cancellation is different, and `status` cannot
tell them apart because a cancellation is recorded as failed on purpose;
`signer_can_retry` is what separates them.

And the page no longer frames a PDF: every document opens in a new tab, where
the browser displays a PDF and anything else downloads. The sentence promising
a preview had been true when it was written.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01GP9ZnyKyjjFfBmv3evRGV3
DELETE answered `"erased": true` and listed what it had erased. It no longer
erases unless asked to: with no parameters it purges -- the documents and the
container go, and who signed stays -- so the old response was a promise eeID had
stopped keeping.

The chapter is two sections now, because they answer two different people. A
purge is you finishing with a document. An erasure is somebody exercising a
right against you, named with `signer_id_code`, or `erase_signers` for everybody
on the document. The purge section says in so many words that it does not answer
a data-subject request, since that is the mistake the old wording invited.

The erasure section is also more careful than it was. It said the container goes,
full stop. It does not when somebody else signed the same document: it is the
other signers' only proof that they signed, and deleting it would answer one
person's request by destroying other people's records. Their identity code
survives inside it -- which is why `erasure.retained` exists and why this is
worth a sentence rather than a footnote, as the controller is the one who has to
tell the data subject.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01GP9ZnyKyjjFfBmv3evRGV3
@github-actions

Copy link
Copy Markdown

Docs Preview

Preview deployed successfully.

Access it here: https://internetee.github.io/eeID-DOC/previews/pr-16/

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant