Mint, inspect, and retire signing keys

Mint a signing key in a context, list and inspect the keys a context holds, replace one whose label is out of date, 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.

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.

Prerequisites

  • A running VTA. See Quickstart.

  • pnm installed and connected to the VTA.

    cargo install pnm-cli@0.23.1 --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:

pnm --vta <vta-slug> keys create \
    --key-type ed25519 \
    --context  my-app \
    --label    "my-app-key-1"
Key created:
  Key ID:          m/26'/2'/2'/0'
  Key Type:        ed25519 (classical signing)
  Derivation Path: m/26'/2'/2'/0'
  Public Key:      z6MkvZqY2CbpWQmbjuuNshtAptH8qbFaCGk3w6Jt72xBXiGi
  Status:          active
  Label:           my-app-key-1
  Created At:      2026-09-16 10:24:07 +08:00

The bracketed part of Key Type is the key’s quantum posture: classical signing means a quantum computer running Shor’s algorithm could break it, while ML-DSA keys show post-quantum signing. 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.

List the keys a context holds

pnm --vta <vta-slug> 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

pnm --vta <vta-slug> keys get "m/26'/2'/2'/0'"
Key ID:          m/26'/2'/2'/0'
Key Type:        ed25519 (classical signing)
Derivation Path: m/26'/2'/2'/0'
Public Key:      z6MkvZqY2CbpWQmbjuuNshtAptH8qbFaCGk3w6Jt72xBXiGi
Status:          active
Label:           my-app-key-1
Created At:      2026-09-16 10:24:07 +08:00
Updated At:      2026-09-16 10:24:07 +08:00

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. The private half stays on the VTA unless an admin with key-export rights exports it, and an internal key’s private half is never exported.

Replace a key whose label is out of date

A key’s label is set when the key is minted. To give a key a label that matches its current use, mint a new key with that label in the same context, as in Mint a key, move your application to the new key, then revoke the old one as shown below.

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:

pnm --vta <vta-slug> keys revoke "m/26'/2'/2'/0'"
Key revoked:
  Key ID:     m/26'/2'/2'/0'
  Status:     revoked
  Updated At: 2026-09-16 11:02:41 +08:00

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

pnm --vta <vta-slug> 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:

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

curl -X POST "https://<vta-url>/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 with cannot sign with a revoked key, which confirms the revocation took effect rather than only changing a displayed status.

Troubleshooting

SymptomLikely causeFix
pnm keys create fails with admin role requiredMinting 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 contextkeys 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 IDThe 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 callThe 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 listRevocation 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: give an application its own identity and have it sign with a key you minted here.

  Keys and contexts: how keys derive from one master seed and why contexts isolate them.

  Grant and revoke access: control which DIDs can reach the keys in a context.