WalletHandlers
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#
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#
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);
}
});
See all 3 lines
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 |
|---|---|---|
|
| Emitted when a new session token is created. The payload contains the token and initial session data. |
|
| Emitted when a session is updated. The payload includes the updated session data. A common use is to check for |
|
| 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.`);
});