# Service identity

> Which WebVH Hosting services hold their own did:webvh identifier, which keys each identity carries, how that identity is provisioned, and how its keys rotate without cutting off peers.

A hosting service that exchanges messages with VTAs and other services needs an identity those peers can resolve and verify, and keys it can replace without breaking every conversation in flight.

Each WebVH Hosting service that takes part in messaging holds its own did:webvh identifier, minted at setup, and rotates its keys through overlapping identity generations. Peers holding a cached copy of the old DID document keep reaching the service while they catch up. [Deploy on Affinidi Portal →](/products/affinidi-elements/webvh-hosting/get-started/webvh-affinidi-portal.md)
Affinidi-hosted appliance

The appliance provisions its Server DID through your VTA when you activate it, and Affinidi operates its keys for you. The rest of this page describes how a service identity works, which you manage directly only when you self-host.

## Server DID

The Server DID is the did:webvh identifier a service presents when it authenticates to, or exchanges DIDComm v2.1 or Trust Spanning Protocol (TSP) messages with, another party.

- Standalone services: the control plane, edge server, and witness each mint their own Server DID and keys.

- Unified daemon: the embedded services share a single Server DID and secrets configuration.

- Watcher: has no Server DID and no secrets, because it takes part in no messaging.

## What keys a service identity holds

Each service keeps three private keys in its configured secrets backend:

| Key | Type | What it does |
| Signing key | Ed25519 | Signs the service’s DID log entries. |
| Key-agreement key | X25519 | Decrypts DIDComm messages addressed to the service. |
| JWT signing key | Ed25519 | Signs the access tokens the service issues to its own callers. Always generated locally. |

The secrets backend also holds the key material of retired identity generations while their grace period runs, and, in VTA-managed mode, the VTA credential bundle the service uses to re-authenticate with its VTA.

## How the service identity is provisioned

At setup time, you choose how the service’s own identity is provisioned. The identity mode is set with mode in the [identity] section of the configuration.

| Mode | How it works |
| VTA-managed (vta, default) | A parent [Verifiable Trust Agent (VTA)](/products/affinidi-elements/vta.md) provisions the service’s did:webvh identifier, its signing key, its key-agreement key, and a signed did.jsonl log. Provisioning runs online against the VTA, or offline through a sealed bundle for hosts that cannot reach it. The only mode available to standalone services. |
| Self-managed (self-managed) | The daemon generates all of its keys locally and builds and self-hosts its own did:webvh identifier. No VTA is required, and the daemon is its own trust root. Unified daemon only, and fixed at setup. |

In VTA-managed mode, the VTA can also mint a long-term admin identity for the service during provisioning. Setup prints it as Admin DID. It is separate from the operator you add to the service’s ACL, which you choose at a different setup prompt.

Inbound provisioning from external VTAs behaves identically in both modes, because identity mode only changes how the service’s own identity is obtained.

## How service keys rotate without cutting off peers

A peer that has cached the service’s DID document keeps encrypting to the key it found there until its cache expires. WebVH Hosting keeps those messages decryptable by rotating through identity generations: each generation is one version of the service’s keys, mediator, and supported protocols.

When the service publishes an update to its own DID that changes any of these, the previous generation is retired rather than deleted:

| Part of the identity | What happens to the old one |
| Key-agreement key | Still decrypts messages until the grace period ends: one hour by default, set with rotation_grace_period under [identity]. |
| Signing key | Replaced immediately as the DID’s update key. Peers with a stale document accept new signatures once they re-resolve the DID. |
| Mediator | Still listened on until the grace period ends, so messages queued there arrive. |

- Peers need to do nothing. They pick up the new keys the next time they resolve the DID.

- Expired generations are dropped by a sweep that runs every minute.

- Rotation is safe by design. The service keeps its current key-agreement key rather than rotate to one its secrets backend does not hold.

- Who runs rotation: the control plane for the whole unified daemon, and each service on its own in a standalone deployment.

### Managing generations

On a self-hosted deployment, admins can see and retire generations in three places:

- Management UI: the Key Generations section of the Settings page.

- API: the admin-only identity endpoints.

- CLI: identity-list, identity-rotate-keys, and identity-retire-now, run with the service stopped.

Retire a generation early only when its key is compromised. Peers whose cached document still names that key reach the service again once their cache expires.

## Related

  [Overview](/products/affinidi-elements/webvh-hosting/overview.md)

  [Roles and access](/products/affinidi-elements/webvh-hosting/concepts/roles-and-access.md)

  [DID lifecycle](/products/affinidi-elements/webvh-hosting/concepts/did-lifecycle.md)
