Skip to content

Verifying Event Signatures

This guide explains how to verify the integrity and authenticity of events returned by EventSourcingDB. You'll learn how signatures work, how to validate them, and what to consider when using them in your application.

Signed Events

When EventSourcingDB is started with the --signing-key-file flag, it automatically signs every event that is returned by the API. This includes events returned when:

The signature is calculated using Ed25519, a modern and efficient digital signature algorithm. The signing key must be a PKCS#8-encoded Ed25519 private key in PEM format.

Here's what a signed event looks like. Pay special attention to the signature field, which includes the prefix esdb:signature:v1:. This prefix indicates the origin and version of the signature format, making it easier to identify and verify signatures in distributed systems – and to distinguish those generated by EventSourcingDB from others:

{
  "specversion": "1.0",
  "id": "0",
  "time": "...",
  "source": "https://library.eventsourcingdb.io",
  "subject": "/books/42",
  "type": "io.eventsourcingdb.library.book-acquired",
  "datacontenttype": "application/json",
  "data": {
    "author": "Arthur C. Clarke",
    "isbn": "978-0756906788",
    "title": "2001 – A Space Odyssey"
  },
  "predecessorhash": "...",
  "hash": "...",
  "signature": "esdb:signature:v1:..."
}

If no signing key is configured, the signature field will still be included, but its value will be null:

"signature": null

Signatures Are Ephemeral

EventSourcingDB does not store signatures permanently. They are calculated on the fly when an event is returned. If the signing key changes, previously returned events will receive different signatures.

You can still validate those events, but only if you fetch them again. Verifying a cached signature is only possible if the signing key hasn't changed in the meantime.

Verifying Events

EventSourcingDB does not persist signatures, nor does it provide a built-in endpoint for signature verification. Instead, clients are responsible for verifying signatures locally – using the provided event fields, the public signing key, and standard cryptographic libraries.

Each event returned from EventSourcingDB includes a hash and, if signing is enabled, a signature. To verify the authenticity of an event:

  1. Recalculate the hash

    Hashing is performed in three steps:

    • First, concatenate the following metadata fields using a pipe (|) as a separator – without any spaces before or after the separator:

      specversion | id | predecessorhash | timestamp | source | subject | type | datacontenttype

      Then compute the SHA-256 hash of this string – this is the metadata hash.

    • Next, compute the SHA-256 hash of the event's data field – this is the data hash.

    • Finally, concatenate both metadata and data hashes (as hexadecimal strings) and compute another SHA-256 hash over the result. This is the final event hash.

  2. Extract the raw signature

    The signature field, if present, starts with the prefix esdb:signature:v1:. This prefix is not part of the actual signature and must be removed before verification. The versioning allows future changes to the format while remaining backward-compatible.

    For signature:v1, the remaining part is a hex-encoded Ed25519 signature of the event's hash.

    This means the signature is computed using the Ed25519 algorithm over the event hash and then encoded as a lowercase hexadecimal string. The result is appended to the prefix esdb:signature:v1: to form the complete signature field value.

  3. Validate the signature

    Use the public key corresponding to the private key configured in the EventSourcingDB instance to verify the signature against the event's hash. The public key must be obtained through a secure, out-of-band mechanism.

If your application requires signatures, treat unsigned events or signature mismatches as errors. If you only need to ensure data integrity, verifying the hash alone is sufficient.

Hash vs. Signature

The hash ensures that the event's content is intact. The signature proves that it originated from a trusted, signing-enabled EventSourcingDB instance.

Hash vs. Signature

EventSourcingDB uses hashes to ensure that the event data has not been modified. Every event contains a hash field, which is computed from the full content of the event.

This mechanism guarantees data integrity, even if no signing key is configured.

If a signing key is configured, EventSourcingDB also provides a signature field. This enables authenticity checks, ensuring that the event was not only unmodified but also issued by a trusted instance of EventSourcingDB.

You can verify the integrity of an event using just the hash. Verifying authenticity requires the signature as well.

Hash Always Available, Signature Optional

Every event has a hash, even if the database was not started with a signing key. The signature field, on the other hand, is only non-null if signing is enabled.

Key Rotation and Its Implications

Because EventSourcingDB does not store signatures, they are always generated on the fly using the currently active signing key.

This has important consequences:

  • The same event may receive different signatures at different points in time, if the signing key has changed.
  • Previously fetched signatures become unverifiable after a key rotation.
  • To verify an event, you must re-fetch it from the database, so it gets signed with the current key.

Avoid Long-Term Caching of Signatures

Never store a signature with the expectation that it will remain valid forever. Signatures are valid only with respect to the current key. If the key changes, so do the signatures.

However, even if the signing key is rotated, hash verification continues to work as expected – because the hash is based on the event content and does not depend on any external key.

Generating a Signing Key

You can generate a signing key using OpenSSL. The key must be Ed25519 and encoded in PKCS#8 format:

openssl genpkey -algorithm ED25519 -out my-key.pem

The resulting file can be passed to EventSourcingDB using the --signing-key-file CLI flag.

Private Key Only

EventSourcingDB only needs the private key in PKCS#8 PEM format. The corresponding public key can be extracted separately, if needed, using standard OpenSSL tools.

When to Use Signature Verification

Event signature verification is particularly useful in scenarios where:

  • Events are exchanged across system boundaries.
  • You want to ensure end-to-end authenticity, e.g., for compliance or auditing purposes.
  • You're building systems with untrusted clients or require cryptographic proof of origin.

For example, if events are transmitted from a service in one data center to a processing pipeline in another, signatures help prove that the data has not been tampered with in transit.

If you simply want to check for accidental corruption or ensure consistency between services, hash validation is usually sufficient.

Best Practices

To make signature verification reliable and secure in production systems, consider the following best practices:

  • Always verify the hash before checking the signature.
  • Never store or transmit signatures as permanent values.
  • Treat missing or invalid signatures as errors only if your application explicitly requires authenticity.
  • Distribute public keys securely and track key rotation procedures carefully.
  • Use built-in verification helpers provided by the official EventSourcingDB client SDKs whenever possible.