Skip to main content

eduID Wallet Matching Portal

The eduID Wallet Matching Portal enables Dutch educational institutions to authenticate users via their eduID wallet credentials, seamlessly linking wallet-based digital identities to institutional accounts. At its core, the portal performs privacy-preserving HMAC-based identity matching and leverages the SURFconext federation for institutional authentication. Whether a user logs in through the traditional federated path (via eduID and SURFconext) or through a wallet-based path (via the OID4VP protocol), the Security Token Service produces identical OIDC tokens. This means downstream systems -- student information systems, learning management platforms, document repositories -- never need to know which authentication method was used. They simply receive a standard access token and ID token containing the user's canonical identity attributes.


The Problem

Students and staff at Dutch educational institutions already have institutional accounts that are accessible through the SURFconext federation and their eduID. These accounts carry institutional identifiers -- the eduID (unique to the institution) and the eduPersonPrincipalName -- that are woven into every layer of institutional IT infrastructure. Student information systems use them. Learning management systems use them. Document management, library access, exam platforms, grade registries -- they all depend on these identifiers to know who a user is.

At the same time, the world is moving toward digital wallet credentials. Students increasingly carry verifiable credentials in mobile wallet applications, including eduID credentials issued by SURFconext. These wallet credentials are cryptographically bound to the holder's device through a public-private key pair and contain identity attributes like the eduPersonPrincipalName. The wallet proves identity by presenting a Verifiable Presentation signed with the holder's private key.

Here lies the fundamental challenge: while the wallet credential does contain useful identity attributes (like the eduPersonPrincipalName), it does not contain the institution-scoped eduID that backend systems depend on. The credential's holder key -- the cryptographic key that signed the presentation -- has no inherent connection to the institution-scoped eduID. The institution's entire infrastructure expects that eduID, and the only way to obtain it is through SURFconext federation.

Crucially, the system does not accept just any wallet credential. The portal defines exactly which credentials are trusted for authentication via DCQL (Digital Credentials Query Language) queries. Only a valid eduID credential from a trusted issuer triggers the matching and reconciliation process. An arbitrary credential from an unknown issuer is rejected before any identity resolution begins.

A naive solution would be to store a mapping table: "public key X belongs to eduid Y." But this creates a privacy risk -- plaintext identifiers sitting in a database, vulnerable to breach, creating a permanent link between a person's wallet identity and their institutional identity. It also creates a dependency problem: what happens when the mapping service is unavailable? What about GDPR compliance -- how do you honor a right-to-erasure request when identifiers are scattered in plaintext?

The eduID Wallet Matching Portal solves this with a cryptographic approach. It never stores plaintext identifiers. All lookups happen via HMAC-hashed values with domain-separated keys. Cached identity attributes are encrypted at rest with separate encryption keys. Compromise of one cryptographic key does not affect others. The entire architecture is designed so that deleting a single set of key material renders all associated identity data irrecoverable -- true crypto-shredding that satisfies GDPR requirements by design, not by policy.


System Overview

System Architecture

The portal is composed of four services that collaborate to authenticate users, match identities, and issue standardized tokens:

  • Portal (Next.js BFF) -- The user-facing application running on port 3000. It implements the Backend-for-Frontend pattern: the browser communicates only with the Portal, which proxies all requests to backend services. It renders the login page, displays QR codes for wallet authentication, and manages user sessions through NextAuth.js v5.

  • Service-STS (Security Token Service) -- A full OAuth2/OIDC authorization server running on port 8080. It handles the standard OIDC protocol dance (authorize, token, userinfo), supports upstream federation to SURFconext, and delegates wallet authentication to the Auth Bridge. Regardless of how authentication occurs, the STS mints the final tokens that downstream systems consume.

  • Service-Auth-Bridge (Authentication Bridge) -- The identity matching and reconciliation engine running on port 8090. It manages OID4VP sessions, verifies Verifiable Presentations from wallets, performs HMAC-based identity matching against the database, and orchestrates the reconciliation flow when a wallet holder is encountered for the first time.

  • PostgreSQL -- The shared persistence layer storing identity matches, link bindings, sessions, and encrypted auxiliary data. All sensitive data is encrypted at rest. All identifier lookups use HMAC hashes rather than plaintext values.


Three Authentication Paths

The portal supports three distinct authentication paths, all of which converge on the same output: a standard OIDC token from the STS.

Federated Login

The traditional path. A user clicks "Login with institution account," is redirected through SURFconext to their institutional identity provider, authenticates, and returns with a set of claims that the STS projects into a canonical token. This is the baseline experience that institutions already know from existing SURFconext integrations.

Wallet Login (Known Holder) -- Fast Path

For returning wallet users. The user scans a QR code and presents their eduID credential from their wallet. The Auth Bridge verifies the credential (checking it is from a trusted issuer), extracts the holder key, and finds an existing identity match. The cached canonical attributes -- including the institution-scoped eduID obtained during the original reconciliation -- are decrypted and used to issue a token immediately. No external calls to SURFconext are required. This path resolves in sub-second time, making wallet login faster than traditional federation.

Wallet Login (New Holder) -- Reconciliation

For first-time wallet users. The user scans the QR code and presents their eduID credential. The credential is verified and the holder key is extracted, but the Auth Bridge has never seen this holder key before. Although the credential contains the eduPersonPrincipalName, it does not contain the institution-scoped eduID. The user is asked to perform a one-time institutional login through SURFconext, which provides the institution-scoped eduID. This links their wallet's holder key to their institutional identity. Once this reconciliation is complete, every subsequent wallet login uses the fast path. The user never needs to authenticate through SURFconext again for wallet-based access.

For a detailed technical walkthrough of each flow, including sequence diagrams and step-by-step descriptions, see the Authentication Flows page.


Key Design Principles

The architecture of the portal is guided by several non-negotiable design principles that prioritize privacy, security, and interoperability.

Zero Plaintext Identifiers in the Database

No eduid, no email address, no name is ever stored in plaintext in the database. All identifier lookups use HMAC-SHA256 hashes. Cached identity attributes are encrypted using AES-256-GCM. If you dump the database, you see hashes and ciphertext -- never a human-readable identifier.

Domain-Separated Cryptographic Keys

The system uses three distinct cryptographic keys for three distinct purposes: Key A for hashing holder key fingerprints, Key B for hashing institutional identifiers, and Key C for encrypting cached attributes. These keys are managed in a KMS (Key Management Service) and never coexist in application memory. Compromise of Key A does not help an attacker decrypt attributes protected by Key C, nor does it allow them to reverse hashes created with Key B.

GDPR-by-Architecture

Privacy compliance is achieved through architectural decisions, not through policy documents alone. Data minimization is enforced by only caching the specific claims needed for token issuance. Crypto-shredding is available by deleting key material, which renders all associated encrypted data irrecoverable. Right-to-erasure requests can be honored by deleting a user's identity match and link binding records, with the cryptographic guarantee that no residual plaintext exists anywhere in the system.

Standard OIDC Token Output

Downstream systems receive standard OAuth2 access tokens and OIDC ID tokens. The claims schema is identical regardless of whether the user authenticated via federation or via their wallet. This means institutions can adopt wallet authentication without modifying any of their existing service provider integrations. The portal is a drop-in enhancement, not a disruptive change.

Configuration-Driven Reconciliation

The reconciliation logic -- how the system handles an unknown wallet holder -- is driven entirely by configuration. Reconciliation selector rules determine which plan to execute based on contextual attributes (credential type, issuer, assurance level). New reconciliation providers can be added without code changes. This makes the system adaptable to future credential ecosystems without engineering effort.


Technology Stack

ComponentTechnology
Portal (Frontend + BFF)Next.js 15, React 19, NextAuth.js v5
Service-STSKotlin/JVM, Ktor, IDK OAuth2
Service-Auth-BridgeKotlin/JVM, Ktor, IDK OID4VP, IDK Reconciliation
DatabasePostgreSQL 15, SqlDelight
CryptographyKMS (Software / Azure Key Vault / AWS KMS)
StandardsOID4VP (DIIP v4), OIDC, RFC 8693, DCQL, SD-JWT

The Kotlin services are built on the Ktor framework, a lightweight asynchronous server framework well-suited for microservice architectures. SqlDelight generates type-safe Kotlin data access code directly from SQL definitions, eliminating raw SQL strings from the application codebase and catching schema mismatches at compile time. The KMS abstraction supports multiple backends -- a software-based KMS for development and testing, Azure Key Vault for Azure-hosted deployments, and AWS KMS for AWS-hosted deployments -- all behind a unified API.



Built on the IDK

The eduID Wallet Matching Portal is not built from scratch. It is built on the open-source Sphereon Identity Development Kit (IDK), which provides the foundational building blocks for identity, cryptography, and credential handling.

The IDK provides the low-level building blocks that the portal's services depend on. This includes: cryptographic primitives for hashing, encryption, and digital signatures; KMS integration with pluggable backends (software, Azure Key Vault, AWS KMS); full OID4VP protocol support including request object creation, Verifiable Presentation verification, and the Universal Verifier; DID (Decentralized Identifier) resolution and management; SD-JWT (Selective Disclosure JWT) handling for credential presentation; DCQL (Digital Credentials Query Language) support for specifying which credential attributes to request from a wallet; the identity matching engine that performs HMAC-based lookups and manages identity link bindings; the reconciliation orchestration framework that evaluates selector rules and executes reconciliation plans; and encrypted attribute persistence with envelope encryption.

The IDK ensures that the portal speaks the right cryptographic and protocol languages without reimplementing standards from scratch. For more details, see the IDK documentation.

The portal's application code focuses on user experience and institutional integration, while the foundational identity, cryptography, matching, and reconciliation logic is handled by the well-tested, reusable IDK libraries.