Migrating from Verifier (v1) to Verifier2
This guide helps you migrate from the original Verifier service (which supports OID4VP Draft 14 and Draft 20) to Verifier2 (which supports OID4VP 1.0 final specification).
The original Verifier service is deprecated and will be removed in Q2 2026. We recommend migrating to Verifier2 for all new projects and planning migration for existing production deployments.
Key Differences at a Glance
| Aspect | Verifier (v1) | Verifier2 |
|---|---|---|
| OID4VP Version | Draft 14, Draft 20 | 1.0 (final specification) |
| Port (Docker Compose) | 7003 | 7004 |
| Port (Standalone) | 7003 | 7003 |
| Request Structure | Single flat request body | Structured: flow_type + core_flow + flow-specific attributes |
| Credential Query | request_credentials | dcql_query (DCQL standard) |
| Policies | Separate vp_policies and vc_policies arrays | Nested under policies object |
| URL Configuration | Headers (authorizeBaseUrl, successRedirectUri, errorRedirectUri) | Request body fields (url_config, redirects) |
| Flow Selection | Implicit (via preset or config) | Explicit via flow_type field |
| Session Endpoint | POST /openid4vc/verify | POST /verification-session/create |
Request Structure Changes
Verifier (v1) Request Example
curl -X 'POST' \
'http://localhost:7003/openid4vc/verify' \
-H 'authorizeBaseUrl: openid4vp://authorize' \
-H 'successRedirectUri: https://example.com/success' \
-H 'errorRedirectUri: https://example.com/error' \
-H 'Content-Type: application/json' \
-d '{
"request_credentials": [
{
"format": "jwt_vc_json",
"type": ["VerifiableCredential", "OpenBadgeCredential"]
}
],
"vp_policies": [],
"vc_policies": [
"signature",
"expired"
]
}'
Verifier2 Equivalent
curl -X 'POST' \
'http://localhost:7004/verification-session/create' \
-H 'Content-Type: application/json' \
-d '{
"flow_type": "cross_device",
"url_config": {
"url_host": "openid4vp://authorize",
"url_prefix": "http://localhost:7004/verification-session"
},
"redirects": {
"successRedirectUri": "https://example.com/success",
"errorRedirectUri": "https://example.com/error"
},
"core_flow": {
"dcql_query": {
"credentials": [
{
"id": "my_credential",
"format": "jwt_vc_json",
"meta": {
"type_values": [
["VerifiableCredential", "OpenBadgeCredential"]
]
}
}
]
},
"policies": {
"vc_policies": [
{ "policy": "signature" },
{ "policy": "expired" }
]
}
}
}'
Breaking Changes
1. Request Body Structure
v1: Single flat JSON object
v2: Structured with flow_type, core_flow, and flow-specific sections
Migration: Decompose your v1 request into:
flow_type— Choosecross_device,same_device, ordc_apicore_flow— Move credential queries and policies hereurl_config— Move URL settings here (no longer in headers)redirects— Move redirect URLs here (no longer in headers)
2. Credential Query Format
v1: request_credentials with simple type array
{
"request_credentials": [
{
"format": "jwt_vc_json",
"type": ["VerifiableCredential", "OpenBadgeCredential"]
}
]
}
v2: dcql_query using the DCQL standard
{
"dcql_query": {
"credentials": [
{
"id": "my_credential",
"format": "jwt_vc_json",
"meta": {
"type_values": [
["VerifiableCredential", "OpenBadgeCredential"]
]
}
}
]
}
}
Key Changes:
- Each credential query requires a unique
id typebecomesmeta.type_values(array of arrays to support alternatives)- DCQL adds support for claim-level queries via
claimsarray
3. Policy Configuration
v1: Separate top-level arrays
{
"vp_policies": [],
"vc_policies": ["signature", "expired"]
}
v2: Nested under policies object with explicit policy objects
{
"policies": {
"vc_policies": [
{ "policy": "signature" },
{ "policy": "expired" }
],
"vp_policies": []
}
}
Key Changes:
- Each policy is now an object with a
policyfield (allows for policy arguments in future) - Nested under
policiesobject instead of top-level
4. URL Configuration
v1: Passed via HTTP headers
-H 'authorizeBaseUrl: openid4vp://authorize' \
-H 'successRedirectUri: https://example.com/success' \
-H 'errorRedirectUri: https://example.com/error'
v2: Passed in request body
{
"url_config": {
"url_host": "openid4vp://authorize",
"url_prefix": "http://localhost:7004/verification-session"
},
"redirects": {
"successRedirectUri": "https://example.com/success",
"errorRedirectUri": "https://example.com/error"
}
}
Key Changes:
authorizeBaseUrl→url_config.url_hostsuccessRedirectUrianderrorRedirectUri→ nested underredirectsobject- New
url_config.url_prefixfield (was implicit in v1)
5. Endpoint Changes
| Operation | Verifier (v1) | Verifier2 |
|---|---|---|
| Create verification session | POST /openid4vc/verify | POST /verification-session/create |
| Get session result | GET /openid4vc/session/{id} | GET /verification-session/{id}/info |
6. Response Format Changes
v1 Session Response:
"openid4vp://authorize?..."
v2 Session Response:
{
"sessionId": "abc123",
"bootstrapAuthorizationRequestUrl": "openid4vp://authorize?...",
"fullAuthorizationRequestUrl": "openid4vp://authorize?..."
}
Key Changes:
urlfield split intobootstrapAuthorizationRequestUrl(short) andfullAuthorizationRequestUrl(with all params)
Configuration File Changes
Verifier (v1) Config
baseUrl: "http://localhost:7003"
authorizeBaseUrl: "openid4vp://authorize"
Verifier2 Config
clientId: "verifier2"
clientMetadata: {
client_name: "My Verifier"
logo_uri: "https://example.com/logo.png"
}
urlPrefix: "http://localhost:7003/verification-session"
urlHost: "openid4vp://authorize"
See Verifier Service Configuration for complete configuration documentation.
