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

AspectVerifier (v1)Verifier2
OID4VP VersionDraft 14, Draft 201.0 (final specification)
Port (Docker Compose)70037004
Port (Standalone)70037003
Request StructureSingle flat request bodyStructured: flow_type + core_flow + flow-specific attributes
Credential Queryrequest_credentialsdcql_query (DCQL standard)
PoliciesSeparate vp_policies and vc_policies arraysNested under policies object
URL ConfigurationHeaders (authorizeBaseUrl, successRedirectUri, errorRedirectUri)Request body fields (url_config, redirects)
Flow SelectionImplicit (via preset or config)Explicit via flow_type field
Session EndpointPOST /openid4vc/verifyPOST /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 — Choose cross_device, same_device, or dc_api
  • core_flow — Move credential queries and policies here
  • url_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
  • type becomes meta.type_values (array of arrays to support alternatives)
  • DCQL adds support for claim-level queries via claims array

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 policy field (allows for policy arguments in future)
  • Nested under policies object 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:

  • authorizeBaseUrlurl_config.url_host
  • successRedirectUri and errorRedirectUri → nested under redirects object
  • New url_config.url_prefix field (was implicit in v1)

5. Endpoint Changes

OperationVerifier (v1)Verifier2
Create verification sessionPOST /openid4vc/verifyPOST /verification-session/create
Get session resultGET /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:

  • url field split into bootstrapAuthorizationRequestUrl (short) and fullAuthorizationRequestUrl (with all params)

Configuration File Changes

Verifier (v1) Config

verifier.conf
baseUrl: "http://localhost:7003"
authorizeBaseUrl: "openid4vp://authorize"

Verifier2 Config

verifier-service.conf
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.


Last updated on May 20, 2026