Delete an IOTA Identity
There are two approaches to delete an IOTA Identity, with different implications:
Deactivate
As detailed in the IOTA DID Method Specification, the state controller of an IOTA Identity may deactivate it by publishing an update that either:
- deletes the contents of the DID Document entirely, leaving the state metadata empty, OR
- sets the
deactivated
field in the DID Document metadata totrue
.
In both cases, the DID Document will be marked as deactivated
when resolved.
This operation is reversible: the identity can subsequently be reactivated at any time, by publishing an update restoring the DID Document's contents, or unsetting the deactivated
field in the metadata respectively, depending on how it was initially deactivated.
Note that the governor (if different from the state controller) cannot deactivate an identity directly because it is disallowed from updating the DID Document, but it may destroy it.
Example
The following example demonstrates deactivating and reactivating an IOTA DID Document, and optionally reclaiming the storage deposit.
// Copyright 2020-2022 IOTA Stiftung
// SPDX-License-Identifier: Apache-2.0
import { Client, MnemonicSecretManager } from "@iota/client-wasm/node";
import { Bip39 } from "@iota/crypto.js";
import { IotaDocument, IotaIdentityClient } from "@iota/identity-wasm/node";
import { IAliasOutput, IRent, TransactionHelper } from "@iota/iota.js";
import { API_ENDPOINT, createDid } from "../util";
/** Demonstrates how to deactivate a DID in an Alias Output. */
export async function deactivateIdentity() {
const client = new Client({
primaryNode: API_ENDPOINT,
localPow: true,
});
const didClient = new IotaIdentityClient(client);
// Generate a random mnemonic for our wallet.
const secretManager: MnemonicSecretManager = {
mnemonic: Bip39.randomMnemonic(),
};
// Creates a new wallet and identity (see "0_create_did" example).
let { document } = await createDid(client, secretManager);
const did = document.id();
// Resolve the latest state of the DID document, so we can reactivate it later.
// Technically this is equivalent to the document above.
document = await didClient.resolveDid(did);
// Deactivate the DID by publishing an empty document.
// This process can be reversed since the Alias Output is not destroyed.
// Deactivation may only be performed by the state controller of the Alias Output.
let deactivatedOutput: IAliasOutput = await didClient.deactivateDidOutput(did);
// Optional: reduce and reclaim the storage deposit, sending the tokens to the state controller.
const rentStructure: IRent = await didClient.getRentStructure();
deactivatedOutput.amount = TransactionHelper.getStorageDeposit(deactivatedOutput, rentStructure).toString();
// Publish the deactivated DID document.
await didClient.publishDidOutput(secretManager, deactivatedOutput);
// Resolving a deactivated DID returns an empty DID document
// with its `deactivated` metadata field set to `true`.
let deactivated: IotaDocument = await didClient.resolveDid(did);
console.log("Deactivated DID document:", JSON.stringify(deactivated, null, 2));
if (deactivated.metadataDeactivated() !== true) {
throw new Error("Failed to deactivate DID document");
}
// Re-activate the DID by publishing a valid DID document.
let reactivatedOutput: IAliasOutput = await didClient.updateDidOutput(document);
// Increase the storage deposit to the minimum again, if it was reclaimed during deactivation.
reactivatedOutput.amount = TransactionHelper.getStorageDeposit(reactivatedOutput, rentStructure).toString();
await didClient.publishDidOutput(secretManager, reactivatedOutput);
// Resolve the reactivated DID document.
let reactivated: IotaDocument = await didClient.resolveDid(did);
if (reactivated.metadataDeactivated() === true) {
throw new Error("Failed to reactivate DID document");
}
}
Destroy
Alternatively, an IOTA Identity can be permanently destroyed.
This is achieved by the governor of a DID publishing a transaction consuming the Alias Output containing the IOTA DID Document, without a corresponding Alias Output on the output side.
Any coins and tokens in the Alias Output are reclaimed and can be sent to another address.
Destroying an IOTA Identity is permanent and irreversible.
Note that historical versions may still be stored off-ledger or on a permanode, so sensitive or Personal Identifiable Information (PII) should NEVER be stored in a DID Document. Even with a previous version available, a destroyed DID can never be restored.
Example
The following example demonstrates a governor destroying an IOTA Identity and sending the storage deposit back to itself.
// Copyright 2020-2022 IOTA Stiftung
// SPDX-License-Identifier: Apache-2.0
import { Client, MnemonicSecretManager } from "@iota/client-wasm/node";
import { Bip39 } from "@iota/crypto.js";
import { IotaIdentityClient } from "@iota/identity-wasm/node";
import { API_ENDPOINT, createDid } from "../util";
/** Demonstrates how to delete a DID in an Alias Output, reclaiming the storage deposit. */
export async function deleteIdentity() {
const client = new Client({
primaryNode: API_ENDPOINT,
localPow: true,
});
const didClient = new IotaIdentityClient(client);
// Generate a random mnemonic for our wallet.
const secretManager: MnemonicSecretManager = {
mnemonic: Bip39.randomMnemonic(),
};
// Creates a new wallet and identity (see "0_create_did" example).
const { address, document } = await createDid(client, secretManager);
const did = document.id();
// Deletes the Alias Output and its contained DID Document, rendering the DID permanently destroyed.
// This operation is *not* reversible.
// Deletion can only be done by the governor of the Alias Output.
const destinationAddress = address;
await didClient.deleteDidOutput(secretManager, destinationAddress, did);
// Attempting to resolve a deleted DID results in a `NotFound` error.
let deleted = false;
try {
await didClient.resolveDid(did);
} catch (err) {
deleted = true;
}
if (!deleted) {
throw new Error("failed to delete DID");
}
}