# Rotate an integration's admin DID

> Mint a fresh admin DID for a mediator, WebVH host, or other admin-scoped integration by re-running its provisioning flow with --admin-template.

By the end of this guide, an admin-scoped integration holds a freshly minted admin DID, and its previous one no longer has access.

Use this when an admin-scoped integration’s admin DID (a mediator, a WebVH host, or another admin-scoped integration) is compromised, lost, or due for rotation. Rotating this admin DID isn’t a standalone operation: it rides along with re-running the same provision-request / provision-integration flow used to provision the integration in the first place, this time passing --admin-template vta-admin. The VTA mints a fresh admin did:key, binds it to the integration’s context, and updates the access control list (ACL), while re-rendering the integration’s own DID material in the same bundle.
Note

This flow always grants the admin role, scoped to the integration’s context, and re-renders the integration’s own DID material at the same time. Plan for both to change together: the admin DID rotates as part of re-provisioning the integration, rather than on its own.

Use this for admin-scoped integrations, such as a mediator or WebVH host.

For a least-privilege application identity that only needs to sign, use [auth-credential create --role application](/products/affinidi-elements/vta/integration-guides/provisioning-app-signing.md) instead, and see [Rotate an application credential](/products/affinidi-elements/vta/vta-management/rotate-application-credential.md) to replace one.

Use this guide when:

- An integration’s admin private key has been exposed, or you suspect it has.

- An integration’s admin DID is due for rotation under your own key-rotation policy.

- You are migrating an integration to new infrastructure and want it to present a new admin identity.

You do not need this guide for an application credential that only signs or reads; see [Rotate an application credential](/products/affinidi-elements/vta/vta-management/rotate-application-credential.md) instead.

## When to use this

| Situation | What to do |
| Compromised admin private key | Re-run provisioning with --admin-template vta-admin: revoke old, mint new |
| Routine key rotation policy | Same re-run |
| First provisioning (setup to long-term DID) | Already handled by passing --admin-template vta-admin on the integration’s initial provision-request |
| Lost admin DID, no access to VTA | A super-admin must run pnm acl create with a new DID manually |

## How it works

The VTA mints a fresh admin did:key and delivers it, together with the integration’s re-rendered DID material, as a [sealed bundle](/products/affinidi-elements/vta/concepts/sealed-transfer.md), the same mechanism every credential-bearing VTA operation uses. The steps below walk through it: generate a request, send it, hand the bundle to the integration’s own setup tooling, then revoke the old admin DID once the new one is confirmed working.

## Prerequisites

- 
A running VTA. See [Quickstart](/products/affinidi-elements/vta/get-started.md).

- 
[Install Rust 1.95 or later](https://www.rust-lang.org/tools/install) on your machine.

- 
pnm installed and connected to the VTA.

```bash
cargo install pnm-cli@0.16.4 --locked --registry crates-io
```

- 
Admin access scoped to the integration’s context, or super-admin access to the VTA.

## Step 1: Generate a new provision request

Use the same --template this integration was originally provisioned with (for example didcomm-mediator or did-hosting-control), and add --admin-template vta-admin to roll the admin DID over in the same request.

```bash
pnm bootstrap provision-request \
    --template        \
    --admin-template vta-admin \
    --context-hint   my-app \
    --label          my-app-admin-rotation \
    --out            my-app-rotation-req.vp.json
```

## Step 2: Send the request to the VTA

Note the SHA-256 digest from stdout. Keep it out-of-band from the bundle file.

```bash
pnm bootstrap provision-integration \
    --request  my-app-rotation-req.vp.json \
    --context  my-app \
    --out      my-app-rotation-bundle.armor
```

The VTA re-renders the integration’s DID material from --template, mints a new admin did:key under its own key custody because --admin-template was set, binds authorisation to it, and adds it to the ACL. The old admin DID is left in the ACL until you remove it in Step 5.

## Step 3: Verify the bundle

This bundle carries the integration’s re-rendered DID material and the new admin authorisation together, not a standalone admin credential, so pnm bootstrap open --out <path> refuses to write it out as a plain credential file. Inspect and verify it instead:

```bash
pnm bootstrap open \
    --bundle        my-app-rotation-bundle.armor \
    --expect-digest 
```

This checks the digest against the value from Step 2, verifies the authorisation VC, and prints a summary: the template name, how many DIDs it carries key material for, the template outputs, and the VTA URL. A digest mismatch stops here rather than printing anything.

## Step 4: Install the new credentials

pnm bootstrap open prints the payload; it does not write it into the integration’s keystore. That install step is specific to each integration and belongs to its own setup tooling, the same tooling that consumed the bundle when the integration was first provisioned. An integration built on the VTA SDK does this through the SDK’s provisioning client rather than by hand.

Whatever performs the install, these are the fields it must place:

| Field in the bundle | Where it goes |
| secrets[<integration-did>] | The integration’s own signing and key-agreement keys, into its keystore. |
| secrets[<admin-did>] | The new long-term admin DID keys, persisted as the integration’s admin identity. This is the half that completes the rotation. |
| outputs (for a did:webvh template) | The did.jsonl log content, saved to disk and published at the URL supplied in Step 1. |
| VTA trust bundle | The VTA DID, root key, and context ID, so the integration trusts inbound DIDComm from this VTA. |
| The authorisation VC | Archive it for audit. The VTA’s ACL is the authority in steady state, so this credential is never re-verified after the first open. |

Once the install completes, tokens issued to the previous admin DID expire within 15 minutes. After that, any call using the old DID returns 401.
Secret hygiene

my-app-rotation-bundle.armor carries HPKE-sealed admin key material, and my-app-rotation-req.vp.json is bound to the ephemeral seed that opens it. Delete both once the integration has installed the credential, and keep both out of source control.

Keep the digest from Step 2 on a separate channel from the bundle. A digest travelling alongside the file it is meant to vouch for confirms nothing, because anyone who can replace the bundle can replace the digest with it.

Rotate immediately, rather than at the next scheduled rotation, if the bundle or the seed directory is ever exposed.

## Step 5: Revoke the old admin DID

The old admin DID is not removed automatically. It retains ACL access until you delete it.

```bash
pnm acl delete 
```

Once deleted, any token issued to the old DID is rejected at its next refresh, within 15 minutes. If the key was compromised, do this immediately.

## Confirm

### Test 1: the new admin DID is in the ACL

```bash
pnm acl list --context my-app
```

Both the new and the old admin DID appear at this point. Run this before Step 5, so you confirm the replacement exists before removing what it replaces.

### Test 2: the integration operates with the new admin DID

Exercise an admin-scoped operation through the integration itself, such as the action its setup tooling performs on first boot. It completes without re-authenticating as the old DID.

### Test 3: the old admin DID is gone

```bash
pnm acl list --context my-app
```

The old admin DID is absent and the new one remains.

## Next steps

  [Grant and revoke access](/products/affinidi-elements/vta/vta-management/acl-management.md): manage roles and context scope for all DIDs registered with the VTA.

  [Rotate an application credential](/products/affinidi-elements/vta/vta-management/rotate-application-credential.md): the equivalent flow for a least-privilege application identity.
