The trust problem
A BAP publishes bap_uri in every context object. That address receives callbacks from providers it has never contracted with — that openness is the point of the network.
It also means the endpoint is reachable by anyone who knows the URL. Without verification, an attacker could POST a fabricated on_search advertising cheap charging that does not exist, or a fake on_confirm carrying an authorization token for a charger they do not operate.
Two mechanisms answer this. The registry establishes who is a legitimate participant. Signatures prove a given message actually came from one of them.
The registry
A network-level directory maintained by the Network Operator. Every participant is a subscriber with a record:
| Field | Meaning |
|---|---|
subscriber_id | Usually the domain, e.g. cpo.electreefi.in |
subscriber_url | Where this participant receives messages |
type | BAP, BPP, BG or BPP-side variants |
domain | Which network, e.g. ev-charging:uei |
signing_public_key | The Ed25519 public key used to verify signatures |
encr_public_key | Public key for encryption where used |
valid_from / valid_until | Key validity window — what makes rotation possible |
status | SUBSCRIBED, INITIATED, UNSUBSCRIBED |
The registry is the network's root of trust. A participant not in it, or not SUBSCRIBED, is not part of the network no matter what its messages claim.
How signing works
The sender signs a digest of the request body with its Ed25519 private key and puts the result in an Authorization header:
Authorization: Signature keyId="cpo.electreefi.in|key-1|ed25519",
algorithm="ed25519",
created="1786518000",
expires="1786518030",
headers="(created) (expires) digest",
signature="Base64EncodedSignatureValue=="Verification is mechanical:
- Parse
keyIdto get the subscriber ID and key identifier. - Look that subscriber up in the registry and fetch
signing_public_key. - Confirm the subscriber is
SUBSCRIBEDand the key is within its validity window. - Recompute the digest of the received body.
- Verify the signature over the signing string.
- Check
createdandexpiresto reject replays.
A gateway that forwards a message adds its own X-Gateway-Authorization alongside the original. Both are meaningful: one proves the originator, the other proves the forwarder. Verify both when you are downstream of a gateway.
What signature verification actually buys
| Check | Prevents |
|---|---|
| Signature valid | Forged messages from non-participants |
Subscriber is SUBSCRIBED | Messages from removed or suspended participants |
| Key within validity window | Use of rotated or revoked keys |
created/expires window | Replay of a previously valid message |
bpp_id matches keyId | A real participant impersonating another |
The last row is easy to miss. A valid signature proves the message came from someone on the network, not that it came from the party it claims to be. If context.bpp_id says cpo.electreefi.in but the signature belongs to a different subscriber, that is impersonation by a legitimate participant — and only a cross-check catches it.
Key management
- Rotate on a schedule. The
valid_fromandvalid_untilfields exist so a new key can be published and become active without an outage. Overlap the windows. - Never put private keys in application config. They belong in a key vault or HSM, with the signing operation behind an interface.
- Support multiple active keys. During rotation, inbound messages may be signed with either the old or the new key, so verification must accept both while the windows overlap.
- Have a revocation runbook. Compromise means updating the registry immediately and rotating — know who can do that and how long it takes before you need it.
Production lessons
- Verify every inbound message. No exceptions, no bypass flag for staging. Unverified endpoints do not stay internal.
- Cross-check
keyIdagainst the claimedbap_idorbpp_id. - Cache registry lookups for minutes. Never make the registry a synchronous dependency on every request.
- Fail closed. If the registry is unreachable and the key is not cached, reject — do not accept unverified traffic to stay available.
- Log verification failures with the subscriber ID and reason. A spike is either an attack or a partner who just rotated keys badly, and you need to tell them apart quickly.
- Reject stale signatures. An unbounded
expireswindow makes replay protection meaningless.
Frequently asked questions
Through a network registry and cryptographic signatures. The registry, maintained by the Network Operator, maps each subscriber ID to its Ed25519 public key and subscription status. Every message carries a signature in the Authorization header that the receiver verifies against that key.
A network-level directory of every participant, holding subscriber_id, subscriber_url, type, domain, signing and encryption public keys, key validity windows and subscription status. It is the network's root of trust — a participant not listed as SUBSCRIBED is not part of the network.
No. A valid signature proves the message came from someone on the network, not from the party it claims to be. You must also cross-check that the keyId matches the bap_id or bpp_id in the context, otherwise a legitimate participant can impersonate another.
Yes, but for minutes rather than hours. Querying the registry on every inbound message makes it a synchronous dependency and a single point of failure, while caching too long means a revoked participant stays trusted. Fail closed if the registry is unreachable and the key is not cached.