Asset Claim
The Asset Claim is used to request that a user prove ownership of a specific on-chain digital asset, such as a Non-Fungible Token (NFT). This is a common requirement for token-gated access, digital ticketing, or verifying possession of a required digital item. The wallet will prompt the user to select an asset that meets the criteria specified by the application.
How it Works#
The process involves the application specifying criteria for an asset. The user's wallet filters their assets and allows them to select one that matches. The wallet then returns the asset's DID and a signature to the application for verification.
Requesting an Asset Claim#
To request an asset, you include an asset
object within the claims
field of your DID Connect request. The claim can be structured in two ways:
- Single Filter Set (Legacy): Define filtering criteria directly on the top-level
asset
object. All criteria are treated as an "AND" condition. - Multiple Filter Sets (Recommended): Use the
filters
array. Each object within the array is a distinct set of criteria ("OR" condition). A user can satisfy the request by providing an asset that matches any one of these sets. The criteria within each object are combined with "AND". This approach provides greater flexibility.
Parameters#
The following parameters can be used to define the criteria for the requested asset, either at the top level (for a single filter set) or within an object in the filters
array.
Parameter | Type | Description |
---|---|---|
|
| A message displayed to the user in the wallet, explaining why the asset is needed. |
|
| If |
|
| The specific DID address of the asset being requested. |
|
| An array of trusted issuer DIDs. The user must present an asset issued by one of these DIDs. An entry can be a DID string or an object like |
|
| An array of DIDs of trusted asset factories. The asset must have been created by one of these factories. |
|
| A specific tag that the asset must have. |
|
| An array of DIDs. The asset's owner must be one of these DIDs. This is rarely used, as the wallet user is typically the owner. |
|
| A flag to filter assets based on whether they have been consumed. |
|
| A URL where the user can obtain the required asset if they do not already have one. |
|
| An array of filter objects. Each object can contain the parameters listed above. This enables complex "OR" logic. |
Example 1: Request a Specific Type of NFT#
This example demonstrates how to request an NFT that meets a single, strict set of criteria. The application requires an asset that was created by a specific factory, issued by the application's own DID, and has a specific tag.
// From your DID Connect request handler
const claims = {
asset: {
description: 'Please provide your TestNFT to continue.',
trustedParents: ['z82n2iL5e2rzK8j8LgAwe3e4o8a7d6e5f4g3'], // Example Factory DID
trustedIssuers: ['zNKk3iL5e2rzK8j8LgAwe3e4o8a7d6e5f4g3'], // Example App DID
tag: 'TestNFT',
}
};
In this scenario, the user's wallet will filter their assets and only show those that match all three conditions: trustedParents
, trustedIssuers
, and tag
.
Example 2: Request an Asset from Multiple Options#
This example uses the filters
array to give the user more flexibility. The application will accept an asset that matches any of the specified conditions. This is useful for accepting different kinds of NFTs that grant the same level of access.
// From your DID Connect request handler
const claims = {
asset: async ({ userDid }) => {
// Dynamically find an asset the user might have created
const { transactions: [tx] } = await client.listTransactions({
accountFilter: { accounts: [userDid] },
typeFilter: { types: ['create_asset'] },
validityFilter: { validity: 'VALID' },
});
const filters = [
// Option 1: A specific type of NFT from our official factory
{
trustedParents: ['z82n2iL5e2rzK8j8LgAwe3e4o8a7d6e5f4g3'], // Official Factory DID
trustedIssuers: ['zNKk3iL5e2rzK8j8LgAwe3e4o8a7d6e5f4g3'], // Official App DID
tag: 'TestNFT',
},
// Option 2: Any NFT created by the user with a specific tag
{
tag: 'NFTCreatedByMe',
},
];
// Option 3: A very specific asset we know the user has created
if (tx) {
filters.push({
address: tx.tx.itxJson.address,
});
}
return {
description: 'Please provide an asset to prove your status.',
filters: filters,
};
},
};
Here, the user can proceed if they have:
- An
TestNFT
from the official factory, OR - An asset with the tag
NFTCreatedByMe
, OR - The specific asset identified by
tx.tx.itxJson.address
.
Handling the Wallet Response#
After the user selects an asset and approves the request, the wallet sends a response to your application's onAuth
callback. This response contains the DID of the presented asset (claim.assetDid
) and a signature (claim.signature
) proving that the user controls the private key associated with the asset's owner.
Your application is responsible for verifying this information.
// Example onAuth callback
const onAuth = async ({ challenge, claims }) => {
const assetClaim = claims.find(x => x.type === 'asset');
if (assetClaim) {
try {
// This function is crucial for security. It must perform three checks:
// 1. Fetch the asset's state from the chain using assetClaim.assetDid
// 2. Verify that the asset state matches the criteria from your original request
// 3. Verify the signature against the challenge and the asset owner's public key
const assetState = await verifyAssetClaim({ claim: assetClaim, challenge });
console.log(`Successfully verified ownership of asset: ${assetState.address}`);
return { successMessage: `You've proven ownership of asset: ${assetState.tags.join(',')}` };
} catch (error) {
console.error('Asset claim verification failed:', error);
return { errorMessage: 'Failed to verify the presented asset.' };
}
}
};
The verifyAssetClaim
function is a critical security step. It ensures the user isn't presenting a fraudulent claim. The implementation will typically involve using a client library (like @ocap/client
) to fetch the asset's current state from the blockchain and then performing cryptographic verification of the signature.
Next Steps#
Verifying ownership is often just the first step. You might want to perform an on-chain action with the asset, such as marking it as "used" or "consumed." This is typically done by requesting a Signature Claim
for a ConsumeAssetTx
in a subsequent step. This pattern ensures the user who presented the asset also authorizes its use. For a detailed walkthrough, see the Signature Claim documentation.
To explore other ways of requesting proof from a user, you can proceed to the following sections.