Defining a verification flow named "kyc" that checks:
The credential type is "KYC Verifiable Credential".
The subject`s age is at least 18.
Why: We want only users who hold a valid KYC credential proving they are over 18 to access a protected resource.
Steps: In src/index.ts, before app.use("/", router) add the following code to set up the Verifier client and define the verification flow:
Verification flow configuration is done using the VerifierClient from the @empe/verifier-client package.
This allows us to define how the verification should be performed and what conditions must be met for a credential to be considered valid.
import { VerifiablePresentation } from '@empe/identity';
import { VerifierConfiguration, VerifierClient } from "@empe/verifier-client";
import jwt from "jsonwebtoken";
const VERIFIER_SERVICE_URL = process.env.VERIFIER_SERVICE_URL; // URL of the Verifier service
const VERIFIER_CLIENT_SECRET = process.env.VERIFIER_CLIENT_SECRET; // Secret to authenticate with Verifier
const JWT_SECRET = process.env.JWT_SECRET; // Secret key used to sign our own JWTs
const verifierConfiguration = {
baseUrl: BASE_URL, // Our app’s public URL, used for callback links
verifierServiceUrl: VERIFIER_SERVICE_URL,
clientSecret: VERIFIER_CLIENT_SECRET,
verificationFlows: [
{
name: "kyc", // Identifier for this verification flow
vpQuery: [ // Requirements for the incoming Verifiable Presentation (VP)
{
fields: [
{
path: ["$.type"], // Inspect the top-level "type" array in the VP
filter: {
type: "array",
contains: { const: "KYC Verifiable Credential" } // Must include this credential type
}
},
{
path: ["$.credentialSubject.age"], // Inspect the age field in credentialSubject
filter: {
type: "number",
minimum: 18 // Age must be at least 18
}
}
]
}
],
handleVerificationResult: (data) => {
// Called after the Verifier service finishes checking the VP
if (data.verification_status === 'verified') {
const { vp } = data;
// Reconstruct the VerifiablePresentation object to read its contents
const vpJSON = VerifiablePresentation.fromJSON(vp);
// Extract the holder's DID (the wallet that presented the VP)
const holder = vpJSON.holder().toString();
// Create a JWT containing the holder DID and the VP payload
// This token can be used by our frontend to grant access to protected routes
const accessToken = jwt.sign({ sub: holder, vp: data.vp }, JWT_SECRET);
return {
access_token: accessToken,
verification_status: data.verification_status,
redirect_url: "/dashboard" // After successful verification, redirect here
};
}
// If not verified, return the raw result (e.g., pending or failed)
return data;
}
}
]
};
// Instantiate the VerifierClient with our Express app and configuration
const verifierClient = new VerifierClient(app, verifierConfiguration);
// Initialize the client, which registers all necessary verification endpoints under the hood
verifierClient.initialize();
Now our app can request a verification QR code and handle verification results.