Handling Results
After creating a presentation request, you need to retrieve the verified claims and determine whether the presentation succeeded. EUDIPLO provides multiple methods for tracking session status and accessing results.
Overviewโ
EUDIPLO offers two primary methods for handling presentation results:
- Webhooks โ Receive asynchronous callbacks when presentations complete (recommended for production)
- Polling/SSE โ Query session status or subscribe to real-time updates
Webhooks (Recommended)โ
Configure webhooks in your presentation configuration or override them at request time to receive verified claims automatically when the presentation completes.
{
"id": "pid-verification",
"dcql_query": { ... },
"webhook": {
"url": "https://verifier.example.com/presentation-callback",
"auth": {
"type": "apiKey",
"value": "your-api-key"
}
}
}
When the presentation completes, EUDIPLO sends a POST request to your webhook URL with the verified claims.
For details on webhook configuration, authentication types, and request format, see Webhooks.
Session Statusโ
Sessions track the presentation request lifecycle from creation through completion or expiration.
Session Statesโ
| Status | Description |
|---|---|
active | Session created, waiting for wallet interaction |
fetched | Presentation request fetched by wallet |
completed | Session successfully completed with verified claims |
expired | Session expired before completion |
failed | Session failed due to an error |
Retrieving Session Statusโ
Query the session status endpoint:
GET /session/{sessionId}
Authorization: Bearer YOUR_JWT_TOKEN
Response:
{
"id": "session-uuid",
"status": "completed",
"type": "presentation",
"createdAt": "2026-01-25T12:00:00.000Z",
"updatedAt": "2026-01-25T12:01:00.000Z",
"consumedAt": "2026-01-25T12:01:00.000Z",
"verifiedClaims": {
"pid-mso-mdoc": {
"given_name": "Jane",
"family_name": "Doe",
"age_over_18": true
}
}
}
Real-Time Updates (Server-Sent Events)โ
For real-time session status updates, subscribe to the SSE endpoint:
GET /session/{sessionId}/events?token=JWT_TOKEN
Authenticationโ
The SSE endpoint requires JWT authentication via a query parameter. This is because the browser's EventSource API does not support custom headers.
| Parameter | Type | Required | Description |
|---|---|---|---|
id | string | Yes | The session ID to subscribe to |
token | string | Yes | Valid JWT access token |
Response Formatโ
The endpoint returns a stream of Server-Sent Events. Each event contains:
{
"id": "session-uuid",
"status": "active|fetched|completed|expired|failed",
"updatedAt": "2024-01-15T12:00:00.000Z"
}
JavaScript Exampleโ
// Get a valid JWT token first
const token = await getAccessToken();
// Create EventSource with token as query parameter
const eventSource = new EventSource(`/session/${sessionId}/events?token=${token}`);
// Handle incoming status updates
eventSource.onmessage = (event) => {
const data = JSON.parse(event.data);
console.log(`Session ${data.id} status: ${data.status}`);
// Close connection when session reaches terminal state
if (['completed', 'expired', 'failed'].includes(data.status)) {
eventSource.close();
// Fetch final result if completed
if (data.status === 'completed') {
fetchSessionResult(data.id);
}
}
};
// Handle connection errors
eventSource.onerror = (error) => {
console.error('SSE connection error:', error);
eventSource.close();
};
Connection Behaviorโ
- Initial Event: Upon connection, the endpoint immediately sends the current session status.
- Auto-reconnect: Browsers automatically reconnect if the connection drops.
- Keep-alive: The server maintains the connection until the client disconnects or the session reaches a terminal state.
Same-Device Redirect Flowsโ
For same-device flows that use a redirect_uri, EUDIPLO generates a one-time response_code and appends it to the redirect URI after the wallet submits its response.
The verifier's frontend receives this code via the redirect and uses it to retrieve the session result. This ensures the browser that initiated the flow is the same one that receives the result.
:::warning Same-device flows with redirect
For same-device flows that use a redirect_uri, the response_code is the only safe way to retrieve the session result. The verifier must extract it from the redirect URL and use it to look up the completed session.
:::
Example redirect:
https://verifier.example.com/callback?response_code=abc123
The frontend extracts response_code and queries:
GET /session/by-code/{response_code}
Authorization: Bearer YOUR_JWT_TOKEN
Single-Use Enforcementโ
All presentation requests are single-use and non-replayable. Once a wallet submits a presentation response:
- The request is marked as consumed
consumedAttimestamp records when the request was first used- Any subsequent attempts to submit presentations for the same request are rejected with
400 Bad Request
This prevents presentation request replay attacks where an attacker could reuse an intercepted request to submit fraudulent credentials.
Session Cleanupโ
Sessions are automatically cleaned up based on tenant-specific retention policies. You can configure:
- TTL (Time-to-Live): How long completed/expired sessions are retained
- Cleanup Mode:
full(default): Deletes the entire session recordanonymize: Keeps metadata (ID, status, timestamps) but removes personal data
For details on session cleanup configuration, see Sessions.
Security Considerationsโ
Direct Post Security Model (OID4VP ยง13.3)โ
EUDIPLO implements the direct_post.jwt response mode with the full security model defined in OID4VP Section 13.3. This model separates identifiers across different actors to prevent session fixation and cross-reference attacks.
Key security fields:
| Identifier | Purpose |
|---|---|
session.id | Internal (backend / verifier) session identifier โ never exposed to the wallet |
walletNonce | Wallet-facing identifier used as state in the authorization request โ cannot be linked to session.id |
nonce | Binds the VP Token to this specific request โ prevents replay attacks |
response_code | One-time code appended to redirect_uri during same-device redirect โ prevents session fixation |
Best Practicesโ
- Use webhooks for production โ More reliable than polling for asynchronous flows
- Validate session state โ Check
status: "completed"before trusting verified claims - Close SSE connections โ Always close
EventSourcewhen session reaches terminal state - Handle timeouts โ Set appropriate timeout values and handle expired sessions gracefully
- Use response_code safely โ For same-device flows, only use
response_codefrom the redirect - Implement token refresh โ Ensure JWT tokens have sufficient lifetime for expected session duration
Error Responsesโ
Session Endpoint Errorsโ
| Status Code | Description |
|---|---|
| 401 | Missing or invalid JWT token |
| 404 | Session not found |
SSE Endpoint Errorsโ
| Status Code | Description |
|---|---|
| 401 | Missing or invalid JWT token |
| 404 | Session not found |
Related Documentationโ
- Webhooks โ Webhook integration patterns
- Sessions โ Session lifecycle and cleanup
- Presentation Configuration โ Configuring webhooks
- Presentation Requests โ Creating requests and redirect URIs
- API Reference โ Session API endpoints