Getting started
Get up and running with the Truvity EUDIW Connector in minutes. This guide walks you through the credential verification flow and helps you create your first presentation request.
How it works
A credential verification flow involves five steps:
-
Your backend creates a presentation request. You call
POST /oidc4vpon the internal management API (port 8081) with a DCQL query specifying the credentials and attributes you need. The connector returns astatevalue for correlation, asame_device_request_urifor deep links, and across_device_request_urifor QR codes. -
You display the request URI to the user. For cross-device flows, render the
cross_device_request_urias a QR code. For same-device flows, redirect the user to thesame_device_request_urideep link. -
The wallet retrieves and displays the request. The EUDI Wallet fetches the signed authorization request from the connector's public protocol endpoint, verifies your X.509 certificate, and displays a consent screen to the user.
-
The user approves and the wallet submits the presentation. The user consents with biometric authentication. The wallet encrypts the presentation and submits it to the connector's public protocol endpoint using the
direct_post.jwtresponse mode. -
The connector verifies credentials and delivers the result. The connector decrypts, verifies signatures, checks revocation, and delivers a
PresentedCredentialsEventto your callback endpoint.
The connector implements OID4VP under the High Assurance Interoperability Profile (HAIP), which defines the required algorithms, response modes, and credential formats for the EUDI Wallet ecosystem. You don't need to configure these protocol options. The connector applies HAIP-compliant settings by default.
- A deployed Truvity EUDIW Connector instance. The connector is not publicly available—contact hello@truvity.com to get access.
Set up your connector
Step 1: Configure your public URL
The connector needs a publicly reachable URL so wallets can send responses.
export CONNECTOR_BASE_URL=https://connector.example.com
Step 2: Generate a test certificate
The connector uses an X.509 certificate to identify itself to wallets.
mkdir -p ./certs
# Generate an EC P-256 private key
openssl ecparam -genkey -name prime256v1 -noout \
-out ./certs/access-key.pem
# Generate a self-signed X.509 certificate (valid for 365 days)
openssl req -new -x509 -key ./certs/access-key.pem \
-out ./certs/access-cert.pem \
-days 365 \
-subj "/CN=My Organization/O=My Organization/C=DE"
# Configure the connector to use the certificate
export CONNECTOR_CERT_PATH=./certs/access-cert.pem
export CONNECTOR_KEY_PATH=./certs/access-key.pem
For production certificates, see Manage certificates.
Step 3: Set up a callback endpoint
The connector delivers verification results to an HTTP endpoint you provide.
# Start a minimal callback server (Node.js)
node -e "require('http').createServer((req, res) => {
let body = '';
req.on('data', c => body += c);
req.on('end', () => { console.log(JSON.parse(body)); res.end('OK'); });
}).listen(3000, () => console.log('Callback listening on :3000'))"
export CONNECTOR_CALLBACK_URL=http://localhost:3000
For production deployments, see Manage certificates and Going to production.
Create a presentation request
Call POST /oidc4vp on the management API with a DCQL query. This example requests a PID (Personal Identification Data) credential with basic identity attributes. The dc+sd-jwt format is the SD-JWT VC credential format used in the EUDI ecosystem.
The VCT (Verifiable Credential Type) values, requested claims, and credential values in this guide are examples. In production, request the attributes required by your use case and available in the target attestation scheme. Available attributes vary by issuer and member state.
- cURL
curl -X POST http://connector:8081/oidc4vp \
-H "Content-Type: application/json" \
-d '{
"dcql_query": {
"credentials": [
{
"id": "pid",
"format": "dc+sd-jwt",
"meta": {
"vct_values": ["urn:eudi:pid:1"]
},
"claims": [
{ "path": ["given_name"] },
{ "path": ["family_name"] },
{ "path": ["birthdate"] }
]
}
]
}
}'
Example response:
{
"state": "abc123",
"same_device_request_uri": "openid4vp://?client_id=...&request_uri=https%3A%2F%2Fconnector.example.com%2Foidc4vp%2Fabc123%2Frequest%3Fflow_type%3Dsame-device",
"cross_device_request_uri": "openid4vp://?client_id=...&request_uri=https%3A%2F%2Fconnector.example.com%2Foidc4vp%2Fabc123%2Frequest%3Fflow_type%3Dcross-device"
}
Store the state value to correlate with the callback later. Both URIs use the openid4vp:// scheme with client_id and request_uri query parameters — pass them to the wallet as-is without parsing. Render cross_device_request_uri as a QR code or redirect the user to same_device_request_uri for same-device flows.
The response contains:
state—a correlation token to match the callback with this request.same_device_request_uri—anopenid4vp://URI for same-device flows. Pass the full URI to the wallet as a deep link.cross_device_request_uri—anopenid4vp://URI to render as a QR code for cross-device flows.
Handle the callback
Implement a callback endpoint that receives the PresentedCredentialsEvent from the connector. The event's status field indicates the verification outcome.
- cURL
# Simulate a FULFILLED callback for testing
curl -X POST http://localhost:3000/callback \
-H "Content-Type: application/json" \
-d '{
"status": "FULFILLED",
"state": "abc123",
"responseCode": "8k5CwzAseoGVK_bHQQJWMw",
"credentials": {
"pid": [
{
"issuer": "https://issuer.example.com",
"claims": {
"given_name": "Erika",
"family_name": "Mustermann",
"birthdate": "1964-08-12"
},
"signatureIsValid": true,
"supportRevocation": false,
"supportTrustAnchor": true,
"isTrusted": false,
"isCertificateRevoked": false,
"kbKeyId": "KrXxHnYsf-Inp0hW1M6r...",
"kbSignatureIsValid": true
}
]
},
"credentialsRaw": {
"pid": [
{
"claims": "eyJiaXJ0aGRhdGUiOiIx...",
"issuer": "https://issuer.example.com",
"kbKeyId": "KrXxHnYsf-Inp0hW1M6r..."
}
]
}
}'
The credentials and credentialsRaw fields are absent for REJECTED, EXPIRED, PROCESSING_ERROR, and VERIFICATION_FAILED statuses. The errorDetails field is present for REJECTED, PROCESSING_ERROR, and VERIFICATION_FAILED statuses. For same-device flows, the event includes a responseCode field to correlate the browser redirect with the callback.
For the complete list of statuses and error codes, see the callback events reference.
You are responsible for applying your own data retention and access control policies to credential data received through callbacks. The connector does not persist credential data after delivering the callback.
Next steps
- KYC verification—verify customer identity using PID credentials
- Passwordless authentication—replace passwords with key binding proof
Further reading
- Connector architecture—how the connector processes requests and delivers results
- OID4VP protocol—the verification protocol the connector implements
- Error codes—wallet-facing HTTP error responses
- Callback events—Presented Credentials Event statuses and payload fields