# Mint, inspect, and retire signing keys

> Mint a signing key in a context, list and inspect the keys a context holds, relabel one, and revoke a key that should no longer sign.

By the end of this guide, you can add a signing key to a context, see what a context already holds, and take a key out of service.

A VTA holds the private half of every signing key it mints and signs on a caller’s behalf, so managing keys means managing records on the VTA rather than files on your machine. For what a key record contains, and how derived keys differ from internal ones, see [Keys and contexts](/products/affinidi-elements/vta/concepts/keys-and-contexts.md).

Without this, a context accumulates keys nobody can account for: minting is not idempotent, so a repeated setup script leaves duplicates behind, and a key that should have been retired keeps signing until someone removes it.

Use this guide when:

- An application needs its own signing key inside a context.

- You want to see which keys a context already holds before adding another.

- A key is being retired, replaced, or was minted by mistake.

- A key’s label no longer describes what it is used for.

You do not need this guide to replace an application’s credential, which is a separate thing from the keys it signs with; see [Rotate an application credential](/products/affinidi-elements/vta/vta-management/rotate-application-credential.md).

## Prerequisites

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

- 
pnm installed and connected to the VTA.

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

- 
Admin access to the VTA. Minting and revoking keys are admin-only operations.

- 
The ID of the context the key belongs to, from pnm contexts list.

## Mint a key

Every context starts with no keys. Mint one so the applications in that context have something to sign with:

```bash
pnm --vta  keys create \
    --key-type ed25519 \
    --context  my-app \
    --label    "my-app-key-1"
```

```text
Key created:
  Key ID:          m/26'/2'/2'/0'
  Key Type:        ed25519
  Derivation Path: m/26'/2'/2'/0'
  Public Key:      z6MkvZqY2CbpWQmbjuuNshtAptH8qbFaCGk3w6Jt72xBXiGi
  Status:          active
  Label:           my-app-key-1
```

The Key ID is the derivation path, not a short opaque identifier. Give every key a --label that says what uses it: the label is the only field that will still mean something to you a year from now.

This command is not idempotent. Running it twice mints two keys, so check what a context already holds before minting into it.
Internal keys are not recoverable

--internal mints a key from the system’s random number generator instead of the master seed. Your mnemonic will not recover it, it is excluded from backups, and no surface will ever export it. If this VTA’s storage is lost, the key is gone permanently, along with the ability to produce any signature it alone was trusted for.

Use it only when a key must be unable to leave the VTA even under administrative authority, and keep a derived key as the default everywhere else.

## List the keys a context holds

```bash
pnm --vta  keys list --context my-app
```

Add --status active to hide keys that have already been revoked. A context with nothing in it reports No keys found.

## Inspect one key

```bash
pnm --vta  keys get "m/26'/2'/2'/0'"
```

```text
Key ID:          m/26'/2'/2'/0'
Key Type:        ed25519
Derivation Path: m/26'/2'/2'/0'
Public Key:      z6MkvZqY2CbpWQmbjuuNshtAptH8qbFaCGk3w6Jt72xBXiGi
Status:          active
Label:           my-app-key-1
```

Quote the key ID in your shell. It contains ' characters, which an unquoted shell will try to interpret.

Public Key is the value a third party needs to check a signature this key produced. It is safe to share, and it is the only half of the pair that ever leaves the VTA.

## Relabel a key

A label is metadata, so changing it affects nothing that the key signs:

```bash
pnm --vta  keys rename "m/26'/2'/2'/0'" --label "my-app-signing-2026"
```

## Retire a key

Revoking marks the key as no longer usable for signing. The record stays, so the key ID keeps resolving and your audit trail still makes sense:

```bash
pnm --vta  keys revoke "m/26'/2'/2'/0'"
```

```text
Key revoked:
  Key ID:     m/26'/2'/2'/0'
  Status:     revoked
```

Mint the replacement and move the application onto it before revoking, rather than after. Signatures the key produced in the past remain verifiable against its public key; revoking stops new ones.

## Confirm

### Test 1: the new key is listed as active

```bash
pnm --vta  keys list --context my-app --status active
```

The key from “Mint a key” appears, with the label you gave it.

### Test 2: the key signs

Ask the VTA to sign a short payload with the key. A base64url-encoded signature comes back, produced without the private key leaving the VTA:

```bash
KEY_ID="m/26'/2'/2'/0'"
KEY_ID_ENCODED=$(printf '%s' "$KEY_ID" | sed "s#/#%2F#g")
TOKEN=$(pnm --vta  auth show-token)

curl -X POST "https:///keys/${KEY_ID_ENCODED}/sign" \
    -H "Authorization: Bearer $TOKEN" \
    -H "Content-Type: application/json" \
    -d '{"payload": "aGVsbG8", "algorithm": "EdDSA"}'
```

The key ID contains / characters, so percent-encode it before putting it in a URL path.

### Test 3: a revoked key no longer signs

Re-run Test 2 against a key you revoked. The VTA refuses it, which confirms the revocation took effect rather than only changing a displayed status.

## Troubleshooting

| Symptom | Likely cause | Fix |
| pnm keys create returns unauthorized | Minting is admin-only, and your session holds a lesser role. | Run pnm auth status to see the identity you are connected as, then use an admin credential. |
| Two keys with the same label in one context | keys create is not idempotent, so a setup script ran twice. | Revoke the duplicate, then list the context to confirm one active key remains. |
| The shell reports a quoting error on a key ID | The ID contains ' characters and was passed unquoted. | Wrap the key ID in double quotes: "m/26'/2'/2'/0'". |
| curl returns 404 on the sign call | The key ID went into the URL without percent-encoding, so / split the path. | Percent-encode the key ID, as in Test 2. |
| A revoked key still appears in pnm keys list | Revocation sets the status rather than deleting the record, so the audit trail stays intact. | Add --status active to list only usable keys. |

## Next steps

  [Sign application payloads without exposing your keys](/products/affinidi-elements/vta/integration-guides/provisioning-app-signing.md): give an application its own identity and have it sign with a key you minted here.

  [Keys and contexts](/products/affinidi-elements/vta/concepts/keys-and-contexts.md): how keys derive from one master seed and why contexts isolate them.

  [Grant and revoke access](/products/affinidi-elements/vta/vta-management/acl-management.md): control which DIDs can reach the keys in a context.
