Dynamic Claims
In many scenarios, the information you need from a user isn't static. You might want to request different data based on who the user is, what device they're using, or other contextual information. DID Connect allows you to define claims dynamically using the onConnect callback.
This approach gives you the flexibility to tailor the authentication experience for each user interaction, rather than relying on a fixed set of claims for every session.
How It Works: The onConnect Callback#
The onConnect callback is a function executed right after the user scans the QR code and their wallet connects to your application, but before any claim requests are sent. This is the ideal moment to inspect the connection context and decide which claims to request.
You can provide this callback at two levels:
- Globally: In the
WalletHandlersconstructor, applying to all configured actions. - Locally: In the
handlers.attach()method, specific to a single action.
If both are defined, the global onConnect runs first, followed by the local one.
The onConnect Flow#
Here is the sequence of events when using a dynamic claim:
Implementing Dynamic Claims#
To implement dynamic claims, pass an onConnect function when you attach your authentication action.
Example: Requesting a Profile#
In this example, we use onConnect to dynamically request the user's full name and email address. This code would be part of your Express.js server setup.
const { WalletHandlers, WalletAuthenticator } = require('@arcblock/did-connect');
const MemoryAuthStorage = require('@arcblock/did-connect-storage-memory');
// ... other imports and server setup
const authenticator = new WalletAuthenticator({ wallet, appInfo }); // Configure as needed
const handlers = new WalletHandlers({ authenticator, tokenStorage: new MemoryAuthStorage() });
handlers.attach({
app: server, // Your express app instance
action: 'login',
onConnect: ({ userDid, didwallet }) => {
console.log(`User ${userDid} connected with wallet:`, didwallet);
// Return an array of claim definitions
return [
{
profile: () => ({
fields: ['fullName', 'email'],
description: 'Please provide your name and email to sign up.',
}),
},
];
},
onAuth: async ({ claims }) => {
// Process the claims received from the wallet
const profile = claims.find((x) => x.type === 'profile');
console.log('User profile:', profile);
return { successMessage: 'Login successful!' };
},
// ... other callbacks like onComplete, onError
});Explanation#
onConnectTrigger: The function is called as soon as the user's wallet scans the QR code.- Context Parameters: It receives an object containing contextual information about the session. The most common properties are:
Parameter | Type | Description |
|---|---|---|
|
| The DID of the user connecting from the wallet. |
|
| Information about the user's wallet, such as |
|
| The Express request object, giving you access to headers, cookies, etc. |
- Return Value: The function should return an array of claim definition objects. Each object's key is the claim type (e.g.,
profile), and its value is a function that returns the specific claim configuration. This structure is identical to how you would define staticclaims.
Advanced Use Case: Halting a Connection#
Besides returning claims, the onConnect callback can be used for access control. If you determine that a user should not proceed, you can throw an error from within the callback. This will halt the authentication process and send an error back to the wallet.
// ...
handlers.attach({
app: server,
action: 'login',
onConnect: ({ userDid }) => {
if (isBanned(userDid)) { // Your custom logic to check if a user is banned
throw new Error('This account has been suspended.');
}
// If not banned, proceed with the claim request
return [
{
profile: () => ({ fields: ['fullName'], description: 'Login to your account.' }),
},
];
},
onAuth: async ({ claims }) => {
// ...
},
});By using onConnect, you can build more intelligent and secure authentication flows that adapt to the context of each connection.
Next, you might want to learn how to link multiple requests together. See our guide on Chaining Workflows to create multi-step user interactions.