Signatures
What BatteryPass signs in each passport version, how the hash and the Ed25519 signature are computed, and how to check them with the published keys.
Every published passport version is signed, so anyone can check that the data comes from your BatteryPass installation and was not changed afterwards. The check needs no account and no call to BatteryPass: the public JSON and the published keys are enough.
What is signed
At publication BatteryPass signs two documents of each version with the active key, in the same transaction that stores them:
| Document | Contains | Hash and signature | Where to read it |
|---|---|---|---|
| Public document | The public tier projection, with labels | public_hash, public_signature | document and verification of the public JSON (getPublicPassport); public_document of getPassportVersion |
| Snapshot | Every field in every tier, with provenance and document references | canonical_hash, signature | snapshot of getPassportVersion, for your organisation |
The public document is what a scanner sees, so anyone can verify it. The snapshot proves the full record to you
and to authorities you show it to. In the public JSON only document is signed; its siblings passport_id,
status, valid_until, verification and links change over the passport's life and are not covered.
{
"algorithm": "Ed25519",
"canonicalization": "RFC8785",
"hash": "sha256:22471733ece6d811d244144731fc505180c5e7760a7a016c1322338bce0f56e5",
"signature": "w0nnz3kjhrEGb1DtMoGp9qlH9g8q0h9YDJRb2jfabq7AOzPMUpnWXoxmIlptgJPTDVy3LWxLQkOpQYuGYXgJ4w",
"key_id": "2027-10-k2",
"signed_at": "2026-10-24T09:15:02Z",
"keys_url": "https://batterypass.example.com/.well-known/batterypass/keys.json"
}How a signature is made and checked
Canonicalise
Serialise the signed object (document, or snapshot) with the JSON Canonicalization Scheme, JCS
(RFC 8785). JCS sorts object members, drops whitespace and writes numbers and strings in one defined form,
so the same data always gives the same bytes. Canonicalise the parsed object, not the response bytes.
Hash
Compute SHA-256 over the canonical bytes and write it as sha256: followed by the lowercase hex digest.
It must equal verification.hash (or public_hash, canonical_hash).
Find the key
Fetch the JWK set from /.well-known/batterypass/keys.json of the BatteryPass address you trust and take the
key whose kid equals verification.key_id. keys_url is not signed: if it points to another address, treat
the check as failed.
Verify
Decode the key's x and the signature from base64url without padding (32 and 64 bytes) and check the
Ed25519 signature over the canonical bytes, not over the hash.
The signature verification guide does this step by step with complete code.
The published keys
The public keys are a JWK set at /.well-known/batterypass/keys.json on your BatteryPass address, outside
/api/v1. It needs no key, may be read from any origin (CORS) and is cacheable for an hour.
{
"keys": [
{ "kty": "OKP", "crv": "Ed25519", "x": "WuoaQRoQuh2kPs5yYB6HxNz3Y58ndE8fRHnzG10NxoU", "kid": "2027-10-k2", "use": "sig", "alg": "EdDSA" },
{ "kty": "OKP", "crv": "Ed25519", "x": "JEpD6r2NnmNrL4_7UWS9wIWLFyjCfaSClypHm110Vl4", "kid": "2026-10-k1", "use": "sig", "alg": "EdDSA" }
]
}The active key is listed first. The operator of your installation rotates keys: a new key signs new versions,
and the old public keys stay in the set so earlier signatures keep verifying. A key that signed a published
version is never removed. Cache keys by kid and fetch the set again when you meet an unknown kid.
Verifying on the server or offline
verifyPassport | Offline verification | |
|---|---|---|
| What it checks | Both signatures and both hashes of a version against the stored documents | The public document you hold, against the published key |
| Result | valid, public_document_valid, snapshot_valid, key_id, version_no, signed_at, checked_at | Your own yes or no |
| Trust | You trust the server's answer | You trust only the key, which you can pin |
| Needs | The passport UUID; version_no optional (default: current version) | The public JSON and the JWK set |
verifyPassport is a convenience for a quick check. For an independent proof, for example in an archive or a
customer's system, verify offline.
A valid signature shows that this BatteryPass installation published exactly this data in this version. It does not say that the data is correct or complete, and it is not a qualified electronic seal under eIDAS.