Skip to content

If there is a suspicion that private keys were compromised, lock the existing user and create a replacement user with new keys. You cannot replace a user's publicKey with v0_UpdateUser.

Prerequisites

Before you refresh the user key, decide what kind of replacement user you need:

  • UI human user: The user creates a new profile with the Ripple Custody authenticator app and shares the new public key. The replacement user should receive the original human-facing alias and loginIds.
  • API or bot user: Generate a new API key pair for the client or bot, then use the new public key when you create the replacement user. Store the new private key in your secrets manager.

Retrieve the existing user's id, metadata.revision, alias, roles, and loginIds. Also prepare:

  • A new UUID for the replacement user.
  • A retired alias for the old user, such as operator-retired-20260618@example.com.
  • Retired loginIds for the old user. Do not set loginIds to null; when present, loginIds must be an array of valid login ID objects.

For more information, see:

Refresh a user key

These steps describe how to refresh a user key with the API.

To refresh a user key:

  1. Get the current user details. For more information, see Manage users and roles.

  2. Create a v0_UpdateUser intent for the existing user that changes the old user's alias and loginIds to retired values. This releases the original alias and login IDs for the replacement user.

    {
      "payload": {
        "reference": {
          "id": "61aaa805-f9b8-11eb-b158-dcfb48cfb3cb",
          "revision": 2
        },
        "alias": "operator-retired-20260618@example.com",
        "roles": ["transaction-operator"],
        "loginIds": [
          {
            "id": "operator-retired-20260618@example.com",
            "providerId": "harmonize"
          }
        ],
        "description": "Retired user record after key refresh",
        "customProperties": {
          "keyRefreshStatus": "retired"
        },
        "type": "v0_UpdateUser"
      }
    }

    If the user has multiple login providers, provide a retired loginIds entry for each provider. Do not use null for loginIds.

  3. Create a v0_LockUser intent to lock the existing user.

    {
      "payload": {
        "reference": {
          "id": "61aaa805-f9b8-11eb-b158-dcfb48cfb3cb",
          "revision": 3
        },
        "type": "v0_LockUser"
      }
    }
  4. Create a replacement user with a new user id, the original alias and loginIds, the required roles, and the newly generated public key.

    {
      "payload": {
        "id": "4d8c6240-3261-4991-9aa9-59e66f089d76",
        "alias": "operator@example.com",
        "publicKey": "MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAE...",
        "roles": ["transaction-operator"],
        "loginIds": [
          {
            "id": "operator@example.com",
            "providerId": "harmonize"
          }
        ],
        "lock": "Unlocked",
        "description": "Replacement user after key refresh",
        "customProperties": {
          "replacesUserId": "61aaa805-f9b8-11eb-b158-dcfb48cfb3cb"
        },
        "type": "v0_CreateUser"
      }
    }

    For a UI human user, use the public key from the user's new authenticator profile. For an API or bot user, use the public key from the newly generated API key pair.

  5. After the intents execute, confirm that the old user is locked and that the replacement user can authenticate and perform the expected read-only operation before allowing state mutation work.

For more information about submitting update, lock, and create-user intents, see Manage intents and approvals and Manage users and roles.