Multi-Step Session
DID Connect can request multiple pieces of information or signatures from a user within a single session. This is accomplished by defining a sequence of claims that the user's wallet will present one after another. This approach is useful for user onboarding, multi-part agreements, or any process that requires several distinct user actions.
This example demonstrates a three-step session that requests a transaction signature, a plain text signature, and a dynamically generated HTML signature.
Example Implementation#
The following configuration sets up a handler for a multi-step session. The core of this implementation is the claims
array, where each element defines a sequential step for the user.
const { fromTokenToUnit } = require('@ocap/util');
const { getRandomMessage } = require('../../libs/util');
const env = require('../../libs/env');
const { wallet } = require('../../libs/auth');
module.exports = {
action: 'claim_multiple_step',
claims: [
{
signature: async () => ({
type: 'TransferV2Tx',
data: {
itx: {
to: wallet.address,
tokens: [
{
address: env.localTokenId,
value: fromTokenToUnit(1, 18).toString(),
},
],
},
},
description: 'Please sign the transaction, you will send 1 token',
}),
},
{
signature: () => ({
type: 'mime:text/plain',
data: getRandomMessage(),
description: 'Please sign the text',
}),
},
{
signature: async ({ userDid, userPk }) => ({
type: 'mime:text/html',
data: `<div>
<h2 style="color:red;font-weight:bold;border-bottom:1px solid blue;">This is title</h2>
<ul>
<li>userDid: ${userDid}</li>
<li>userPk: ${userPk}</li>
</ul>
</div>`,
description: 'Please sign the html',
}),
},
],
onAuth: async ({ userDid, userPk, claims, step }) => {
logger.info('claim.multiStep.onAuth', { step, userPk, userDid, claims });
},
};
Step-by-Step Breakdown#
1. Step 1: Requesting a Transaction Signature#
The first element in the claims
array asks the user to sign a transaction. The wallet will display the details of the TransferV2Tx
and prompt the user for confirmation.
{
signature: async () => ({
type: 'TransferV2Tx',
data: {
itx: {
to: wallet.address,
tokens: [
{
address: env.localTokenId,
value: fromTokenToUnit(1, 18).toString(),
},
],
},
},
description: 'Please sign the transaction, you will send 1 token',
}),
}
2. Step 2: Requesting a Plain Text Signature#
Once the first step is complete, the wallet immediately presents the second request: signing a simple plain text message.
{
signature: () => ({
type: 'mime:text/plain',
data: getRandomMessage(),
description: 'Please sign the text',
}),
}
3. Step 3: Requesting a Dynamic HTML Signature#
The final step demonstrates a dynamic claim. The signature
property is an async
function that receives context about the user, such as userDid
and userPk
. This allows you to generate claim data on the fly. In this case, it creates an HTML snippet that includes the user's DID.
{
signature: async ({ userDid, userPk }) => ({
type: 'mime:text/html',
data: `<div>...</div>`,
description: 'Please sign the html',
}),
}
Visualizing the Flow#
The interaction between the application, the SDK, and the user's wallet follows a clear sequence. The onAuth
callback is only invoked after all steps are successfully completed.
Handling the Final Response#
The onAuth
callback is triggered only after the user has approved all the claims in the sequence. It receives a claims
array containing the results from each step, allowing your application to process them all at once.
onAuth: async ({ userDid, userPk, claims, step }) => {
logger.info('claim.multiStep.onAuth', { step, userPk, userDid, claims });
},
This structured approach enables you to build complex, guided interactions. For more details on configuring different types of claims, refer to the Requesting Claims guide and the Signature Claim reference.