OpenEUDI is open source (MIT) and live on npm.
GitHub: https://github.com/openeudi · npm:@openeudi/coreand@openeudi/openid4vp
Originally published on eidas-pro.com.
Prerequisites
- Node.js 20+ installed
- TypeScript project (or JavaScript with ESM)
- A terminal and your favorite editor
That's it. No API keys, no registration, no WRPAC certificate. DEMO mode works out of the box.
Step 1: Install
npm install @openeudi/core
Or with your preferred package manager:
pnpm add @openeudi/core
yarn add @openeudi/core
Step 2: Create a Verifier
import { VerificationService, DemoMode, InMemorySessionStore } from '@openeudi/core';
// Initialize in DEMO mode — no credentials needed
const service = new VerificationService({
mode: new DemoMode(),
store: new InMemorySessionStore(),
});
The mode option controls how the SDK behaves:
| Mode | Behavior | Use Case |
|---|---|---|
new DemoMode() |
Auto-completes after 3 seconds | Showcases, sales demos, landing pages |
new MockMode() |
Simulates wallet responses with configurable data | Integration testing, CI/CD pipelines |
new ProductionMode(config) |
Real EUDI Wallet verification | Live verifications (requires WRPAC, Dec 2026+) |
Step 3: Create a Verification Session
const session = await service.createSession({ type: 'AGE' });
// session.qrCodeUrl contains a data URL for the QR code image
// session.sessionId is the unique session identifier
// session.deepLink is for mobile-to-mobile flows
The attributes array specifies what you want to verify. eIDAS Pro is designed around privacy-first boolean attributes — you get a yes/no answer, never raw personal data:
| Attribute | Returns | Description |
|---|---|---|
age_over_18 |
Boolean | Is the user 18 or older? |
age_over_21 |
Boolean | Is the user 21 or older? |
age_over_16 |
Boolean | Is the user 16 or older? |
age_over_14 |
Boolean | Is the user 14 or older? |
Country compliance (which countries are allowed) is configured in your merchant settings as a whitelist or blacklist — the SDK checks this automatically without requesting personal data from the user.
Note: In DEMO mode, attributes return synthetic data. In PRODUCTION mode, the wallet cryptographically proves the boolean without revealing the underlying birth date.
Step 4: Display the QR Code
The session includes a QR code that the user scans with their EUDI Wallet app.
// In a web context
const img = document.createElement('img');
img.src = session.qrCodeUrl;
document.getElementById('qr-container').appendChild(img);
// In React
function VerificationQR({ session }) {
return <img src={session.qrCodeUrl} alt="Scan with your EUDI Wallet" />;
}
// In Next.js (using next/image)
import Image from 'next/image';
function VerificationQR({ session }) {
return <Image src={session.qrCodeUrl} alt="Scan with your EUDI Wallet" width={256} height={256} />;
}
Step 5: Listen for the Result
// Event-based (recommended for web apps)
service.on('verified', (result) => {
console.log('Verification successful!');
console.log('Verified:', result.verified); // true
console.log('Country allowed:', result.countryAllowed); // true (based on your whitelist)
console.log('Session ID:', result.sessionId);
console.log('Timestamp:', result.verifiedAt);
});
service.on('failed', (error) => {
console.log('Verification failed:', error.reason);
// 'timeout' | 'rejected' | 'invalid_credential' | 'network_error'
});
service.on('expired', () => {
console.log('Session expired — generate a new QR code');
});
Or use the promise-based API:
try {
const result = await session.waitForResult({ timeout: 120000 }); // 2 min timeout
console.log('Verified:', result.verified);
} catch (error) {
console.log('Failed or timed out:', error.reason);
}
Complete Example: Express.js API Route
import express from 'express';
import { VerificationService, DemoMode, InMemorySessionStore } from '@openeudi/core';
const app = express();
const service = new VerificationService({
mode: new DemoMode(),
store: new InMemorySessionStore(),
});
// Create a new verification session
app.post('/api/verify', async (req, res) => {
const session = await service.createSession({ type: 'AGE' });
res.json({
sessionId: session.sessionId,
qrCodeUrl: session.qrCodeUrl,
});
});
// Check session status (or use SSE for real-time)
app.get('/api/verify/:sessionId', async (req, res) => {
const status = await service.getSessionStatus(req.params.sessionId);
res.json(status);
});
// SSE endpoint for real-time updates
app.get('/api/verify/:sessionId/events', (req, res) => {
res.setHeader('Content-Type', 'text/event-stream');
res.setHeader('Cache-Control', 'no-cache');
res.setHeader('Connection', 'keep-alive');
service.on('verified', (result) => {
res.write(`data: ${JSON.stringify({ type: 'verified', result })}\n\n`);
res.end();
});
service.on('failed', (error) => {
res.write(`data: ${JSON.stringify({ type: 'failed', error })}\n\n`);
res.end();
});
});
app.listen(3000, () => console.log('Server running on port 3000'));
What Happens in DEMO Mode?
When you run this code in DEMO mode:
- A QR code is generated (visually identical to a real one)
- After 3 seconds, the session automatically completes
- Synthetic verification data is returned (age_over_18: true, countryAllowed: true)
- Your
onVerifiedcallback fires with the result
No real wallet is involved. This lets you build and test the entire verification UI and backend flow before EUDI Wallets launch.
Next Steps
- Switch to MockMode to test with configurable responses (success, failure, timeout)
- Add the WooCommerce plugin to your WordPress store for checkout verification
- Read the API reference for advanced configuration (custom QR styles, session options, error handling)
- Join the GitHub discussions at https://github.com/openeudi to report issues or request features
When EUDI Wallets launch in December 2026, switch new DemoMode() to new ProductionMode(config) and add your WRPAC credentials — or use eIDAS Pro's managed service to skip the certificate management entirely.
OpenEUDI is MIT-licensed and available on npm today (@openeudi/core, @openeudi/openid4vp). Star the GitHub repo to follow releases.
Top comments (0)