The WalletHandlers class is a high-level utility designed to seamlessly integrate the DID Connect workflow into an Express.js or similar server-side framework. It automates the setup of all required API endpoints for a given action, handling the communication between your application and the user's DID Wallet.
It works in tandem with the WalletAuthenticator, which manages the cryptographic signing and verification of messages. Since WalletHandlers is built on Node.js's EventEmitter, you can listen for various lifecycle events as the session state changes in your token storage.
Constructor
Creates an instance of the DID Connect handlers. This instance orchestrates the handling of HTTP requests for the DID Connect process.
DID Connect Handler Setup
const { WalletHandlers } = require('@did-connect/handler');
const { WalletAuthenticator } = require('@did-connect/authenticator');
const { FileStorage } = require('@did-connect/storage-file');
// 1. Initialize the authenticator with your app's wallet and info
const authenticator = new WalletAuthenticator({ wallet, appInfo, chainInfo });
// 2. Initialize a storage adapter to manage session state
const tokenStorage = new FileStorage({ dbPath: './sessions.json' });
// 3. Create the handlers instance
const handlers = new WalletHandlers({
authenticator,
tokenStorage,
});Parameters
- config
object(required) — Configuration object for the WalletHandlers instance.- authenticator
WalletAuthenticator(required) — An instance ofWalletAuthenticatorresponsible for cryptographic operations. - tokenStorage
object(required) — A token storage instance that handles session state (e.g.,FileStorage,MongoStorage). - pathTransformer
function— An optional function to transform the URL pathname for the wallet callback, useful in proxy or complex routing scenarios. - onConnect
function— An optional global callback executed when a wallet scans the QR code, before the auth request is sent. It can be used for global permission checks. Throws an error to halt the process. - options
object— An optional object to customize the behavior of the handlers.- prefix
string(default:/api/did) — The URL prefix for all generated endpoints. - cleanupDelay
number(default:60000) — The time in milliseconds to wait before cleaning up a completed session from storage. - tokenKey
string(default:_t_) — The query parameter key for the session token. - encKey
string(default:_ek_) — The query parameter key for the encryption key. - versionKey
string(default:_v_) — The query parameter key for the protocol version.
- prefix
- authenticator
Methods
attach(config)
This is the primary method of the WalletHandlers class. It attaches the necessary DID Connect routes to your Express app for a specific user action (e.g., 'login', 'payment'). This method creates a full set of endpoints to handle the entire connection lifecycle, from token generation to wallet response handling.
Once attached, the following routes are created for the given action:
GET {prefix}/{action}/token: Creates a new session token.POST {prefix}/{action}/token: Creates a new session token.GET {prefix}/{action}/status: Checks the status of a session token (e.g., pending, scanned, approved).GET {prefix}/{action}/timeout: Manually expires a session token.GET {prefix}/{action}/auth: The endpoint for the wallet to fetch authentication requirements.POST {prefix}/{action}/auth: The endpoint for the wallet to submit the signed response.
Parameters
- config
object(required) — Configuration object for attaching the routes.- app
object(required) — The Express app instance. - action
string(required) — A unique name for this workflow (e.g., 'login', 'claim-asset'). This becomes part of the URL. - onAuth
function(required) — The callback executed after the user successfully completes the flow in their wallet. This is where you handle the verified data. - claims
object[]— An optional array of claims to request from the user (e.g., profile, signature). - onStart
function— An optional callback executed when a new session is started. - onConnect
function— An optional callback executed when the wallet scans the code. It overrides the constructor'sonConnectfor this specific action. - onDecline
function— An optional callback executed if the user declines the request in their wallet. - onComplete
function— An optional callback executed after the entire workflow is finished and the session token is destroyed. - onExpire
function— An optional callback for when the session token expires. - onError
function(default:console.error) — An optional callback for handling any errors during the process. - authPrincipal
boolean | string(default:true) — Whether to request anauthPrincipalclaim first to establish the user's DID. - persistentDynamicClaims
boolean(default:false) — Whether to persist dynamically generated claims in the session storage.
- app
Example
Attach Login Handler
const express = require('express');
// ... setup for authenticator and tokenStorage from the constructor example
const app = express();
const handlers = new WalletHandlers({ authenticator, tokenStorage });
handlers.attach({
app,
action: 'login',
claims: [{ type: 'profile' }], // Request user's profile
onAuth: async ({ userDid, claims }) => {
// Core logic after a successful login.
// Find or create a user in your database with userDid.
const profile = claims.find(x => x.type === 'profile');
console.log(`User ${userDid} logged in with name: ${profile.fullName}.`);
// You can now set a cookie or JWT for the user's web session.
},
onComplete: ({ token }) => {
console.log(`Session ${token} completed and cleaned up.`);
},
onError: ({ error }) => {
console.error('An error occurred in the login flow:', error);
}
});
app.listen(3000, () => {
console.log('DID Connect server is running on port 3000');
});Events
Since WalletHandlers extends EventEmitter and listens to the tokenStorage instance, you can subscribe to events to monitor the session lifecycle. This is particularly useful for providing real-time feedback to the user, for example, by using WebSockets to update the UI when a QR code is scanned.
| Event | Payload | Description |
|---|---|---|
created | object | Emitted when a new session token is created. The payload contains the token and initial session data. |
updated | object | Emitted when a session is updated. The payload includes the updated session data. A common use is to check for status: 'scanned'. |
deleted | object | Emitted when a session token is destroyed, either upon completion, expiration, or manual timeout. The payload contains the token that was removed. |
Example
Listening to Session Events
// Assuming 'io' is a Socket.IO server instance attached to your Express app
handlers.on('updated', (payload) => {
// Notify the specific web client that the QR code has been scanned
if (payload.status === 'scanned') {
console.log(`Wallet scanned token: ${payload.token}`);
// The 'sid' (socket ID) should be stored in the session when it's created
if (payload.sid) {
io.to(payload.sid).emit('wallet_scanned');
}
}
});
handlers.on('deleted', ({ token }) => {
console.log(`Token ${token} was deleted from storage.`);
});