Consent Docs

Rotate secrets

Rotate the evidence chain key, change the receipt signing key and other credentials, and know which secrets must never change.

How-to2 min readFor project administrators and deployment operators

Rotate a secret on a schedule or after a suspected leak. Only the evidence chain key rotates with no side effects. Some secrets must never change.

Rotate the evidence chain key#

  1. Create the new secret and store it in your secret manager.

    Shell
    openssl rand -hex 32
  2. Add the new key after the old one, and make it active.

    .envConfig
    EVIDENCE_CHAIN_KEYS=2026a:<old secret>,2026b:<new secret>
    EVIDENCE_CHAIN_ACTIVE_KEY=2026b
  3. Restart every API replica.

    Shell
    docker compose up -d consent-api

New events are sealed with 2026b. Each event records the id of the key that sealed it, so older events still verify.

Keep old chain keys in the list

Never remove a key while evidence sealed with it is kept. Those events would fail to verify.

Change the receipt signing key#

Avoid this. A deployment publishes and checks with one signing key at a time. After a change, older receipts and anchors verify only offline, with the earlier public key. They no longer pass Verify a receipt, POST /sdk/v1/receipts/verify or the signature check of Verify on an anchor.

If you must change it:

  1. Save the public key set you publish now.

    Shell
    curl -s https://consent.example.in/sdk/v1/keys \
      > keys-until-2026-10.json
  2. Create a new seed and store it in your secret manager.

    Shell
    openssl rand -base64 32
  3. Set it as RECEIPT_SIGNING_PRIVATE_KEY, with a new RECEIPT_SIGNING_KEY_ID.

  4. Restart the API.

  5. Tell customers the date of the change and give them the saved key set.

Keep derived keys as dedicated keys#

A deployment that started with only ENCRYPTION_KEY derives its chain key and signing key from it. You can set the same values as dedicated keys, so nothing changes. Treat the output as a secret.

  1. Print the EVIDENCE_CHAIN_KEYS value. For SOURCE_SECRET, use EVIDENCE_SIGNING_KEY if it is set, else RECEIPT_SIGNING_KEY, else ENCRYPTION_KEY.

    Shell
    SOURCE_SECRET="$ENCRYPTION_KEY" node -e "
    const c = require('crypto');
    const secret = Buffer.from(c.hkdfSync(
      'sha256', process.env.SOURCE_SECRET,
      'piedap-consent', 'evidence-chain-v2', 32,
    )).toString('hex');
    const hash = c.createHash('sha256').update(secret).digest('hex');
    console.log('k' + hash.slice(0, 10) + ':' + secret);
    "
  2. Print the RECEIPT_SIGNING_PRIVATE_KEY value. For SOURCE_SECRET, use RECEIPT_SIGNING_KEY if it is set, else ENCRYPTION_KEY.

    Shell
    SOURCE_SECRET="$ENCRYPTION_KEY" node -e "
    const c = require('crypto');
    console.log(Buffer.from(c.hkdfSync(
      'sha256', process.env.SOURCE_SECRET,
      'piedap-consent', 'receipt-ed25519', 32,
    )).toString('base64'));
    "
  3. Set both values, and set SUBJECT_HASH_PEPPER to the value of ENCRYPTION_KEY.

  4. Restart the API.

  5. Check that /sdk/v1/keys shows the same kid as before, and that an older record still shows its chain as verified.

Secrets you never change#

Secret Why
SUBJECT_HASH_PEPPER Every stored identifier hash depends on it. With a new value no record can be found by identifier
ENCRYPTION_KEY There is no tool to encrypt again. A new value makes stored secrets unreadable and every secret key invalid
A project's subject fingerprint key Customers match receipts and webhooks with it. It is created once and kept

Other credentials#

Credential How to change it
PLATFORM_API_KEY, METRICS_TOKEN Set a new value and restart. Update your tooling and scraper
Database and Redis passwords Change them in the service, update the variables and restart
LOGIN_SECRET and the cookie names They follow IAM. Change both sides together
A customer's secret key The customer revokes it on Install and creates a new one
A customer's identity secret The customer rotates it on Install
A webhook signing secret It cannot be changed. The customer creates a new endpoint and deletes the old one

↑↓ to move, Enter to open