Look at the credentials your messaging stack issues. There is probably an API key per account, and possibly scopes on it. That covers "this application may send".
It does not cover the question that actually arises in any integrated system: on whose behalf, and for how long?
Why the gap exists#
Because it did not matter when a platform was called by one backend belonging to one company. The key was the identity, and the answer to "on whose behalf" was "the account holder, obviously".
It stops being obvious the moment anything is layered. A journey engine calls a messaging API for one of its customers. An agent desk sends on behalf of the tenant whose queue it is serving. A partner integration acts for a client who can revoke that arrangement.
In each case the credential says who is calling. Nothing says who they are calling for.
What goes wrong without it#
Revocation is all-or-nothing. A partner's access is a shared key. Withdrawing one customer's authorisation means rotating a credential that everyone else is also using.
Audit answers the wrong question. Logs record which key sent a message. Reconstructing which end customer authorised it means joining application logs that may not have been retained.
Blast radius is the whole account. A leaked integration key can send as anybody the integration serves.
Consent enforcement lands in the wrong place. The system holding the consent ledger is often not the system holding the credential. Without a way to say "I am acting for this subject", the check has to be trusted to the caller — which means it is not a check.
The absence of service identity does not announce itself. It shows up as a sequence of small compromises, each reasonable on its own, and the sequence is the same everywhere.
How a shared secret becomes an incident
- 01One key, one integration
Perfectly fine. It is scoped by accident, because there is only one caller.
- 02A second caller borrows it
Nobody wants to run the provisioning process twice. The key is now shared.
- 03The key acquires scope
It needs to do more, so it is granted more. Nothing revokes the parts it stopped needing.
- 04Rotation becomes impossible
Rotating it means coordinating every holder, and nobody knows who holds it.
- 05A holder is compromised
Now everything the key can do is available, and you cannot tell which holder did what.
The shape of the answer#
The pattern is well established outside this category and rarely applied inside it.
- A short-lived token, not a long-lived key. Minutes, exchanged for a durable credential. A leaked token expires; a leaked key is discovered.
- An explicit subject claim. The token says which end customer this action is for. The receiving system enforces it rather than trusting an argument in the request body.
- Scopes that name capability and audience. "May send utility messages, for tenant X, on channel Y" — not "may use the messaging API".
- A revocation path that is not a rotation. Withdrawing one delegation must not disturb any other.
- An audit record carrying the delegation chain, so the question "who authorised this message" has a stored answer rather than an investigation.
What a service credential has to be
- Verifiable
The recipient can check it without calling the issuer. Signature over a known key, not a lookup.
- Scoped
Names the actions and the resources. A credential that says "trusted" says nothing useful.
- Short-lived
Minutes or hours. Expiry is the property that makes compromise survivable without coordination.
- Attributable
Identifies the calling service, not just the fact of authorisation. Logs need a subject.
- Revocable
Independently, by the issuer, without the holder's cooperation. Otherwise trust is permanent.
- Delegable
A can act for B with proof, within B's scope and never beyond it. This is what federation needs.
Why this is worth doing before you need it#
Because it is nearly impossible to retrofit. Once integrations exist that assume a long-lived key with implicit authority, every one of them has to change, and each is owned by a different team on a different schedule.
The migration is not technically hard. It is politically hard, and it takes a year.
The argument against is always the same: we have three services, we know who they are, this is over-engineering.
It is over-engineering for three services. It is exactly right for the fourth, which will be a partner rather than a team, and it is impossible to retrofit for the eleventh, because by then the shared secret is a load-bearing part of six deployment pipelines.
The cost of doing it early is a week and some unfamiliarity. The cost of doing it late is a migration during which everything still has to work.
The federation connection#
If you are running several systems that call each other rather than one merged system, this is the layer that makes it safe. Published contracts let systems talk. Service-to-service identity is what makes it defensible when someone asks what a system was allowed to do, for whom, and when that permission ended.
Federation without it is a set of shared secrets in configuration files, which is a merge with worse security properties and none of the simplicity.
What to take away#
Give every service a verifiable identity. Issue scoped, short-lived, revocable credentials rather than long-lived shared secrets. Make delegation explicit and provable. Do it while you have three services, because the reason to do it arrives with the fourth and the ability to do it leaves with the tenth.