vaheks / allkiri
Estonian eID for PHP: authenticate and digitally sign with ID-card (Web eID), Mobile-ID and Smart-ID; create and validate ASiC-E / XAdES-LT(A) containers compatible with DigiDoc.
Requires
- php: ^8.2
- composer-runtime-api: ^2.0
- ext-curl: *
- ext-dom: *
- ext-mbstring: *
- ext-openssl: *
- ext-zlib: *
- guzzlehttp/psr7: ^2.12.3
- phpseclib/phpseclib: ^3.0.57
- psr/clock: ^1.0
- psr/http-client: ^1.0
- psr/http-factory: ^1.0
- psr/http-message: ^1.1 || ^2.0
- psr/log: ^3.0
- psr/simple-cache: ^3.0
- web-eid/web-eid-authtoken-validation-php: ^1.3.1
Requires (Dev)
- ext-zip: *
- friendsofphp/php-cs-fixer: ^3.75
- phpstan/extension-installer: ^1.4
- phpstan/phpstan: ^2.1
- phpstan/phpstan-phpunit: ^2.0
- phpstan/phpstan-strict-rules: ^2.0
- phpunit/phpunit: ^11.5
Suggests
- ext-intl: Needed for a Web eID site whose domain name is not ASCII, unless its origin is configured in Punycode
- psr/simple-cache-implementation: Keeps downloaded trusted lists between requests; without a PSR-16 cache each Allkiri instance fetches them again
Provides
None
Conflicts
None
Replaces
None
This package is auto-updated.
Last update: 2026-09-18 11:37:31 UTC
README
Estonian eID for PHP. Sign people in with an ID card, Mobile-ID or Smart-ID, have them sign documents, and check the signatures you receive. The documents are ASiC-E containers with XAdES signatures, the files DigiDoc4 opens.
Status: alpha. Every means has signed people in and signed documents against the production services, by hand, in September 2026, including a Smart-ID QR code and the Smart-ID app on the same phone. Before 1.0 the manual checklist and the production smoke test still have to be run and recorded (releasing.md). The API may change until then.
Why
PHP has only fragments: official authentication-only clients for Web eID,
Mobile-ID and Smart-ID, and no maintained equivalent of digidoc4j or
libdigidocpp for building the signature container. SK's own Mobile-ID PHP
client says it outright: signing is not supported because no such library
exists for PHP. allkiri is that library.
Install
composer require vaheks/allkiri:^0.8@alpha
Until 1.0 every release is an alpha, and Composer installs one only when asked,
which is what @alpha does. The PHP version and extensions it needs are under
Requirements.
Quick start
Everything below runs against SK's free test services with their published test accounts. Going live says what production needs instead.
Sign someone in with Mobile-ID
Two requests: one sends the request to the phone, the page then polls the other until the person answers.
use Allkiri\Allkiri; use Allkiri\Config\Environment; use Allkiri\MobileId\MobileIdConfiguration; use Allkiri\MobileId\MobileIdIdentity; use Allkiri\MobileId\MobileIdSession; $allkiri = new Allkiri(Environment::demo()); $authenticator = $allkiri->mobileIdAuthenticator(MobileIdConfiguration::demo()); // First request: show the code before the person reaches for their phone. $session = $authenticator->start(new MobileIdIdentity('+37200000766', '60001019906')); echo $session->verificationCode; $_SESSION['mid'] = json_encode($session); // Polled from the page: null until they answer. $identity = $authenticator->poll(MobileIdSession::fromJson($_SESSION['mid'])); echo $identity?->semanticsIdentifier(); // "PNOEE-60001019906", the account key
Smart-ID works the same way, by identity code, by QR code, or by opening the Smart-ID app on the same phone. The ID card signs in through the browser with Web eID.
Have them sign a document with Smart-ID
use Allkiri\Container\AsicContainer; use Allkiri\Container\DataFile; use Allkiri\SmartId\DocumentNumber; use Allkiri\SmartId\Interactions; use Allkiri\SmartId\SmartIdConfiguration; $signer = $allkiri->smartIdSigner(SmartIdConfiguration::demo()); $container = AsicContainer::create(DataFile::fromPath('leping.pdf')); // First request. The document number names the person's Smart-ID account; // keep the one they signed in with, or ask their phone for it. $signing = $signer->startNotification($container, new DocumentNumber($documentNumber), Interactions::forText('Sign the lease')); echo $signing->verificationCode(); // Polled from the page, with the same container: null until they answer. $result = $signer->poll($container, $signing); if ($result !== null) { file_put_contents('leping.asice', $allkiri->writer()->write($result->container)); }
The signature is timestamped and carries its revocation answer, so it is XAdES-LT, which DigiDoc4 and SiVa accept. Mobile-ID and the ID card sign the same way.
Check a signed document
$report = $allkiri->validator()->validateFile('leping.asice'); foreach ($report->signatures as $signature) { echo $signature->signedBy(), ': ', $signature->indication->value, "\n"; // "TOTAL-PASSED" }
Going live
allkiri is free. Some of the services behind it are not:
| You want to | You need |
|---|---|
| Sign people in with an ID card | nothing but HTTPS |
| Sign people in with Mobile-ID or Smart-ID | a contract with SK for each, and your server's address registered with SK |
| Have people sign documents | the above for the means you offer, plus SK's timestamping service |
| Check documents you receive | nothing |
Revocation checks and the trusted lists are free. docs/going-live.md covers each service, what it costs, what your server needs, and what to check before the first real person signs.
What it does
- Signing in with the ID card (Web eID), Mobile-ID and Smart-ID, with the verification code, typed outcomes for everything SK publishes, and sessions that survive between two HTTP requests.
- Smart-ID v3 in full: push notifications, QR codes, and the app on the same device with its callback checked. RSASSA-PSS, as SK now requires.
- Signing with any of the three, or with a local key or e-seal, at level B, T, LT or LTA, with ECDSA (P-256, P-384) or RSA (PKCS#1 or PSS). The card's own algorithm is negotiated rather than assumed.
- A two-step API for remote signers:
prepare()hands you a digest and a serialisable session,finalize()takes the value back. - Containers: create, read, and add a signature without disturbing a byte of what was already signed.
- Archive timestamps, so a signature outlasts the algorithms it was made with, applied at signing or years later.
- Validation with verdicts in the vocabulary SiVa and DigiDoc4 use, and an optional second opinion from SiVa itself.
- Trust from the European list of trusted lists, verified against the certificates the Official Journal publishes and following the Commission's changes of them, or from any list you pin yourself.
- A browser helper, dependency-free, that drives the Web eID extension, shows verification codes and draws the Smart-ID QR code. It decides nothing: every answer goes to your server.
Both Estonian card PKIs are handled: IDEMIA cards (SK ID Solutions) and the Thales cards issued since November 2025 (Zetes).
| Guide | |
|---|---|
| docs/going-live.md | the services, contracts and costs production needs |
| docs/signing.md | making a signature, and the two-step API |
| docs/validation.md | reading a verdict, and every finding code |
| docs/mobile-id.md | Mobile-ID |
| docs/smart-id.md | Smart-ID, every flow |
| docs/web-eid.md | the ID card |
| docs/browser.md | the page: assets/allkiri.js |
| docs/frameworks.md | wiring it into Laravel or Symfony |
| docs/logging.md | the audit trail, and what must never reach a log |
| docs/trust.md | trusted lists, and what production trusts |
Try the demo
composer install php -S localhost:8080 -t examples/demo-app/public examples/demo-app/public/index.php
A small application that signs in with any of the three means, signs uploaded files with any of them, archives the result and validates a container. It runs against the free test services, so nothing real is involved, or in live mode against production with your own credentials. See examples/demo-app/README.md, which also shows how to put HTTPS in front of it: the ID card works only over HTTPS.
How it is tested
Not against its own tests alone:
- digidoc4j's containers (ECDSA P-256 and P-384, RSA, LT, LTA, two signatures) verify with our code, and SiVa judges what we produce.
- SK's demo services, nightly: every published Mobile-ID test number and Smart-ID demo account, every documented refusal, QR codes finished by SK's mock scan, and containers that SiVa reports TOTAL-PASSED.
- The live European list of trusted lists, nightly: its signature, the pivot lists that change its signers, and the Estonian authorities behind every means.
- Captured responses from SK's timestamp and OCSP services, and an archive timestamp digidoc4j made, whose coverage we reproduce to the byte.
- Production, by hand, with real cards and phones.
The unit suite runs offline: an in-process timestamp authority and OCSP responder stand in for the real ones. See docs/testing.md.
Requirements
PHP 8.2 or newer with curl, dom, mbstring, openssl and zlib.
intl is optional: a Web eID site whose domain name is not ASCII needs it, or
its origin configured in Punycode.
No zip extension: the container layer reads and writes ZIP itself, because a
validator has to see what ZipArchive does not show, and adding a signature
has to leave the entries already there byte for byte. Running the test suite
does need it, to cross-check what our own writer produced.
Framework-agnostic: bring your own PSR-18 HTTP client, PSR-3 logger and PSR-16 cache, or use the built-in ones. The library never touches sessions, files or databases on its own.
Development
composer install composer check # coding standard + static analysis + unit tests composer test:integration # needs ALLKIRI_INTEGRATION=1, talks to demo services
See CONTRIBUTING.md. Every specification, endpoint and reference implementation this is built against is listed in docs/specs.md, and decisions that took some establishing are recorded in docs/decisions.md.
Security
Report a vulnerability privately, as SECURITY.md describes, not in a public issue.
License
MIT.