a factory pattern, abstracted storage, and event subscriptions. This code is functionally equivalent to the SDK capabilities but uses a distinct architectural structure.
1. Installation
npm install @openeudi/core
2. Verifier Factory and Configuration
Define a configuration interface and a factory function to manage modes.
import { VerificationEngine, SandboxEnvironment, MockEnvironment, ProductionEnvironment } from '@openeudi/core';
import { TransientStorageAdapter } from './storage/TransientStorageAdapter';
export interface EudiConfig {
environment: 'sandbox' | 'mock' | 'production';
storage: any; // Abstracted storage interface
productionCredentials?: {
wrpacCert: string;
clientId: string;
};
}
export class IdentityVerifierFactory {
static create(config: EudiConfig): VerificationEngine {
let env: SandboxEnvironment | MockEnvironment | ProductionEnvironment;
switch (config.environment) {
case 'sandbox':
env = new SandboxEnvironment();
break;
case 'mock':
env = new MockEnvironment();
break;
case 'production':
if (!config.productionCredentials) {
throw new Error('Production credentials required for WRPAC');
}
env = new ProductionEnvironment(config.productionCredentials);
break;
default:
throw new Error(`Unknown environment: ${config.environment}`);
}
return new VerificationEngine({
mode: env,
repository: config.storage,
});
}
}
3. Session Initiation and QR Generation
Create a service method to initiate a verification request. Note the use of claimType and specific boolean attributes.
import { IdentityVerifierFactory, EudiConfig } from './verifier-factory';
import { TransientStorageAdapter } from './storage/TransientStorageAdapter';
const verifier = IdentityVerifierFactory.create({
environment: 'sandbox',
storage: new TransientStorageAdapter(),
});
export async function startAgeCheck(): Promise<{ sessionId: string; qrDataUri: string; deepLink: string }> {
// Request specific boolean claims. The wallet will only return true/false.
const requestPayload = {
claimType: 'AGE_VERIFICATION',
requiredClaims: ['is_adult', 'is_senior'],
countryCompliance: {
strategy: 'whitelist',
allowedRegions: ['EU', 'EEA'],
},
};
const authSession = await verifier.initiateVerification(requestPayload);
return {
sessionId: authSession.identifier,
qrDataUri: authSession.qrCodeDataUri,
deepLink: authSession.mobileRedirectUri,
};
}
4. Asynchronous Result Processing
Use event subscriptions to handle verification outcomes. This decouples the UI from the verification logic.
import { VerificationEvent } from '@openeudi/core';
// Subscribe to verification lifecycle events
verifier.on(VerificationEvent.Completed, (payload) => {
console.log(`Session ${payload.sessionId} completed.`);
console.log(`Is Adult: ${payload.claims.is_adult}`);
console.log(`Country Compliant: ${payload.countryCompliant}`);
// Trigger business logic (e.g., grant access, update user profile)
});
verifier.on(VerificationEvent.Failed, (errorPayload) => {
console.error(`Verification failed: ${errorPayload.reason}`);
// Reasons: 'timeout', 'user_rejected', 'invalid_credential', 'network_failure'
});
verifier.on(VerificationEvent.Expired, (sessionId) => {
console.warn(`Session ${sessionId} expired. QR code is no longer valid.`);
});
5. Promise-Based Alternative
For simpler flows or testing, a promise-based wrapper can be used.
export async function waitForVerificationResult(sessionId: string, timeoutMs: number = 120000): Promise<boolean> {
try {
const result = await verifier.awaitCompletion(sessionId, { timeout: timeoutMs });
return result.claims.is_adult === true && result.countryCompliant;
} catch (err) {
console.error('Verification did not complete within timeout or failed:', err);
return false;
}
}
Rationale for Choices
- Boolean Claims: The
requiredClaims array requests is_adult rather than a date of birth. This enforces privacy by design. The SDK ensures the wallet only returns the boolean result.
- Country Compliance: The
countryCompliance configuration allows the SDK to automatically validate the user's issuing country against a whitelist/blacklist. This removes the need for the application to parse country codes manually.
- Storage Abstraction: Using
TransientStorageAdapter in the example allows for quick setup. In production, replace this with a Redis-backed adapter to support distributed deployments and session persistence.
Pitfall Guide
Developers integrating EUDI verification often encounter specific technical and operational challenges. The following guide highlights common mistakes and their resolutions.
-
Pitfall: Blocking the Main Thread on Verification
- Explanation: Attempting to
await the verification result synchronously in the HTTP request handler will cause timeouts, as the user may take minutes to scan the QR code.
- Fix: Always use event-driven architecture or Server-Sent Events (SSE). Return the QR code immediately and listen for the
Completed event asynchronously.
-
Pitfall: Ignoring Session Expiration
- Explanation: Verification sessions have a limited lifespan. If the UI does not handle expiration, users may attempt to scan expired QR codes, leading to confusion.
- Fix: Implement a client-side timer that matches the session TTL. Automatically refresh the QR code or notify the user when the session expires.
-
Pitfall: Using Sandbox Mode in Production
- Explanation:
SandboxMode auto-completes with synthetic data. Deploying this to production allows any user to bypass verification.
- Fix: Enforce environment checks at startup. Use strict typing and CI/CD pipelines to ensure
ProductionEnvironment is the only mode allowed in release builds.
-
Pitfall: Misunderstanding WRPAC Requirements
- Explanation: Production mode requires a Wallet Relaying Party Accreditation Certificate (WRPAC). Developers may attempt to use production endpoints without this certificate, resulting in authentication failures.
- Fix: Plan for WRPAC acquisition well in advance. Until December 2026, rely on
MockMode for integration testing and SandboxMode for UI validation. Consider managed services if certificate management is a bottleneck.
-
Pitfall: Hardcoding Claim Names
- Explanation: Claim identifiers may vary based on the wallet implementation or regulatory updates. Hardcoding strings like
age_over_18 can lead to brittle integrations.
- Fix: Define claim constants in a centralized configuration module. Validate the response payload structure dynamically and handle missing claims gracefully.
-
Pitfall: Inadequate Error Handling for Network Failures
- Explanation: The verification flow involves communication between the user's wallet and the verifier. Network interruptions can leave sessions in an indeterminate state.
- Fix: Implement retry logic for transient network errors. Log detailed error reasons (
network_error, timeout) and provide clear user feedback. Ensure the session store can recover from partial states.
-
Pitfall: Overlooking Country Compliance Logic
- Explanation: The SDK handles country compliance automatically, but developers must configure the allowed regions. Failing to configure this may result in accepting users from unsupported jurisdictions.
- Fix: Explicitly define
countryCompliance strategies in the verification request. Regularly audit the whitelist/blacklist against current regulatory requirements.
Production Bundle
Action Checklist
Decision Matrix
Use this matrix to select the appropriate SDK mode based on your development stage and requirements.
| Scenario | Recommended Mode | Rationale | Cost Impact |
|---|
| Initial Prototyping | SandboxMode | Auto-completes instantly with synthetic data. No configuration required. | Free |
| Integration Testing | MockMode | Simulates wallet responses with configurable outcomes. Ideal for CI/CD pipelines. | Free |
| Pre-Launch Validation | SandboxMode | Validates UI/UX flows without real wallet interaction. | Free |
| Live Production (Post-Dec 2026) | ProductionMode | Required for real EUDI Wallet interactions. Needs WRPAC credentials. | WRPAC acquisition cost |
| Managed Service Alternative | ProductionMode (via Provider) | Offloads WRPAC management to a third-party provider. | Provider subscription fee |
Configuration Template
Copy this TypeScript configuration template to bootstrap your verification service. Adjust the values based on your environment.
// config/eudi.config.ts
import { EudiConfig } from '../verifier-factory';
import { RedisStorageAdapter } from '../storage/RedisStorageAdapter';
const isProduction = process.env.NODE_ENV === 'production';
export const eudiConfiguration: EudiConfig = {
environment: isProduction ? 'production' : 'sandbox',
storage: new RedisStorageAdapter({
host: process.env.REDIS_HOST || 'localhost',
port: parseInt(process.env.REDIS_PORT || '6379', 10),
ttl: 300, // Session TTL in seconds
}),
productionCredentials: isProduction
? {
wrpacCert: process.env.WRPAC_CERT_PATH || '',
clientId: process.env.EUDI_CLIENT_ID || '',
}
: undefined,
};
Quick Start Guide
Get a basic verification flow running in under five minutes.
- Initialize Project: Create a new Node.js project with TypeScript support.
mkdir eudi-demo && cd eudi-demo
npm init -y
npm install typescript @openeudi/core
npx tsc --init
- Create Verifier Instance: Write a script to initialize the verifier in sandbox mode.
import { IdentityVerifierFactory } from './verifier-factory';
import { TransientStorageAdapter } from './storage/TransientStorageAdapter';
const verifier = IdentityVerifierFactory.create({
environment: 'sandbox',
storage: new TransientStorageAdapter(),
});
- Start Verification: Call the initiation method and log the QR code data.
const session = await verifier.initiateVerification({
claimType: 'AGE_VERIFICATION',
requiredClaims: ['is_adult'],
});
console.log('Scan this QR:', session.qrCodeDataUri);
- Handle Result: Subscribe to the completion event.
verifier.on('completed', (result) => {
console.log('Verification Result:', result.claims.is_adult);
});
- Run: Execute the script. In sandbox mode, the verification will auto-complete after 3 seconds, demonstrating the full flow.
This guide provides the technical foundation for integrating EUDI verification into your applications. By leveraging the OpenEUDI SDK, you can build privacy-preserving, compliant verification systems that align with the future of European digital identity.