Used to check for browser translation.
用于检测浏览器翻译。
ブラウザの翻訳を検出する
API Reference

WalletHandlers


The WalletHandlers class is a server-side component designed to integrate DID Connect into web frameworks like Express.js. It automates the creation of the required API endpoints, simplifying the backend implementation of a DID Connect session. This class works in tandem with the WalletAuthenticator, which handles the cryptographic signing and verification of messages.

WalletHandlers extends Node.js's EventEmitter, allowing you to listen for key events during the authentication lifecycle.

How it Works#

The WalletHandlers class sets up a series of HTTP endpoints for a given action (e.g., 'login'). These endpoints manage the entire DID Connect flow, from generating a session token to receiving the final wallet response.


Constructor#

new WalletHandlers(config)

Creates an instance of the DID Connect handlers. This instance can then be used to attach multiple workflows (actions) to your application.

Parameter

Type

Description

config

object

The configuration object for the handler instance.

config.tokenStorage

object

Required. An object responsible for creating, reading, and destroying session tokens. You can use @did-connect/storage-memory for development or implement your own for production (e.g., using Redis).

config.authenticator

object

Required. An instance of WalletAuthenticator, which handles the cryptographic signing and verification of messages between the app and the wallet.

config.pathTransformer

function

Optional. A function to transform the URL path included in the DID Connect deep link. Defaults to an identity function.

config.onConnect

function

Optional. A global function called just before a claims request is sent to the wallet. It can be used for session validation or permission checks. Throwing an error will halt the process.

config.options

object

Optional. An object for customizing endpoint behavior and parameters.

config.options.prefix

string

The URL prefix for all created endpoints. Defaults to '/api/did'.

config.options.cleanupDelay

number

The delay in milliseconds before a completed session is cleaned up from storage. Defaults to 60000 (1 minute).

config.options.tokenKey

string

The query parameter key for the session token. Defaults to '_t_'.

config.options.encKey

string

The query parameter key for the encryption key. Defaults to '_ek_'.

config.options.versionKey

string

The query parameter key for the protocol version. Defaults to '_v_'.

Example#

const { WalletAuthenticator, WalletHandlers } = require('@did-connect/server');
const { fromRandom } = require('@ocap/wallet');
const TokenStorage = require('@did-connect/storage-memory');

// 1. Configure the authenticator with your app's wallet and info
const appWallet = fromRandom();
const authenticator = new WalletAuthenticator({
wallet: appWallet,
appInfo: {
name: 'My App',
description: 'My App Description',
icon: 'https://example.com/icon.png',
link: 'https://example.com',
},
});

// 2. Create a handler instance
const tokenStorage = new TokenStorage();
const handlers = new WalletHandlers({
authenticator,
tokenStorage,
});

// Now, the 'handlers' instance is ready to have actions attached to it.

Methods#

attach(config)#

The .attach() method is the primary way to configure and enable a specific DID Connect workflow, known as an "action," on your web server. It registers a set of standard routes with your Express app instance.

For an action named {action}, the following routes are created under the configured prefix:

  • GET /{prefix}/{action}/token: Creates a new session token and a deep link URL for the QR code.
  • POST /{prefix}/{action}/token: Also creates a new session token.
  • GET /{prefix}/{action}/status: Allows the web client to poll for the session status.
  • GET /{prefix}/{action}/timeout: Allows the web client to manually expire a token.
  • GET /{prefix}/{action}/auth: Endpoint for the wallet to fetch the claims request.
  • POST /{prefix}/{action}/auth: Endpoint for the wallet to submit the signed response.
  • GET /{prefix}/{action}/auth/submit: Alternative submission endpoint for web wallets.

Parameter

Type

Description

config.app

object

Required. The Express application instance to attach the routes to.

config.action

string

Required. A unique name for this workflow (e.g., 'login', 'payment'). This becomes part of the URL path.

config.claims

object[]

An array of claim objects that your application is requesting from the user. For example, [{ type: 'profile' }].

config.onAuth

function

Required. A callback that executes when the user successfully authenticates in their wallet and the signed response is verified. This is where you handle the received claims. Signature: (req, res, claims) => void.

config.onStart

function

Optional. A callback that runs when a new session token is generated.

config.onConnect

function

Optional. A callback that runs when the wallet scans the QR code and requests the claims. This overrides the global onConnect for this specific action.

config.onDecline

function

Optional. A callback for when the user explicitly declines the request in their wallet. Signature: (req, res, token) => void.

config.onComplete

function

Optional. A callback that runs after the entire process is finished for a session (either success or decline). Useful for final cleanup.

config.onExpire

function

Optional. A callback for when the session token expires before completion.

config.onError

function

Optional. A callback for handling any errors that occur during the process. Defaults to console.error.

config.authPrincipal

boolean | string

Optional. Specifies if an authPrincipal claim should be automatically added to authenticate the user's DID. Defaults to true.

config.persistentDynamicClaims

boolean

Optional. If set to true, dynamically generated claims will be persisted in storage. Defaults to false.

Example#

This example sets up a simple login flow on an Express server.

const express = require('express');
const { WalletAuthenticator, WalletHandlers } = require('@did-connect/server');
const { fromRandom } = require('@ocap/wallet');
const TokenStorage = require('@did-connect/storage-memory');

const app = express();
const port = 3000;

// 1. Configure Authenticator
const appWallet = fromRandom();
const authenticator = new WalletAuthenticator({
wallet: appWallet,
appInfo: {
name: 'My Express App',
description: 'A simple DID Connect login example',
icon: 'https://arcblock.oss-cn-beijing.aliyuncs.com/images/wallet-round.png',
link: `http://localhost:${port}`
},
});

// 2. Configure Handlers
const tokenStorage = new TokenStorage();
const handlers = new WalletHandlers({
authenticator,
tokenStorage,
});

// 3. Attach a "login" action to the Express app
handlers.attach({
app,
action: 'login',
claims: [
{ type: 'profile', fields: ['fullName', 'email', 'avatar'] }
],
onAuth: (req, res, claims) => {
// This function is called upon successful authentication
const userProfile = claims.find(x => x.type === 'profile').fields;
console.log('User authenticated:', userProfile.fullName);

// Here, you would typically create a user session or JWT for your app
// The session status in tokenStorage is automatically updated to 'succeed'.
},
onDecline: (req, res, token) => {
console.log(`User declined session: ${token}`);
},
});

app.listen(port, () => {
console.log(`Example app listening on port ${port}`);
console.log(`To start a login session, open: http://localhost:${port}/api/did/login/token`);
});

Events#

Since WalletHandlers is an event emitter, you can listen for changes in the session store.

  • created: Emitted when a new session token is created. (data)
  • updated: Emitted when a session's state changes (e.g., from 'created' to 'scanned', then to 'succeed'). (payload)
  • deleted: Emitted when a session token is destroyed after completion or expiration. ({ token })

Example#

handlers.on('updated', (payload) => {
console.log('Session updated:', payload.token, 'Status:', payload.status);
// You could use this event to push updates to the client via WebSockets.
});


With WalletHandlers, you can quickly set up a robust backend for any DID Connect workflow. For more complete, end-to-end implementations, please see the Simple Login example.