Policy Configuration Levels

The verification policy system supports multiple levels of policy configuration, allowing fine-grained control over which policies are applied to which credentials and presentations. This document explains how policies can be configured at different scopes based on the implementation in the verifier libraries.

Policy Configuration Structure

Policies are organized into a hierarchical structure

data class DefinedVerificationPolicies(
    /** Policies to run on the presentations (VP-level) */
    val vp_policies: VPPolicyList? = null,
    
    /** Policies to run on all credentials (Global VC-level) */
    val vc_policies: VCPolicyList? = null,
    
    /** Policies to run on specific credential query IDs (Specific VC-level) */
    val specific_vc_policies: Map<String, VCPolicyList>? = null
)

Policy Levels Explained

1. VP-Level Policies (vp_policies)

Scope: Applied to Verifiable Presentations themselves, before credential extraction.

Purpose: Validate presentation-level properties such as:

  • Presentation signature (holder binding)
  • Audience matching
  • Nonce validation
  • Presentation format-specific checks (e.g., SD hash for SD-JWT, device auth for mdoc)

When Applied:

  • First in the verification flow
  • Applied to each presentation in the vp_token response
  • Format-specific: policies are organized by presentation format (jwt_vc_json, dc+sd-jwt, mso_mdoc)

Example Configuration:

{
  "vp_policies": {
    "jwt_vc_json": [
      "jwt_vc_json/audience-check",
      "jwt_vc_json/nonce-check",
      "jwt_vc_json/envelope_signature"
    ],
    "dc+sd-jwt": [
      "dc+sd-jwt/audience-check",
      "dc+sd-jwt/nonce-check",
      "dc+sd-jwt/kb-jwt_signature",
      "dc+sd-jwt/sd_hash-check"
    ],
    "mso_mdoc": [
      "mso_mdoc/device-auth",
      "mso_mdoc/issuer_auth",
      "mso_mdoc/issuer_signed_integrity",
      "mso_mdoc/mso"
    ]
  }
}

Default Behavior: If not specified, default policies are applied based on the presentation format:

  • jwt_vc_json: audience-check, nonce-check, envelope_signature
  • dc+sd-jwt: audience-check, nonce-check, kb-jwt_signature, sd_hash-check
  • mso_mdoc: device-auth, device_key_auth, issuer_auth, issuer_signed_integrity, mso

Available Policies:


2. Global VC-Level Policies (vc_policies)

Scope: Applied to all credentials extracted from all presentations, regardless of which query they satisfy.

Purpose: Enforce universal credential requirements such as:

  • Signature verification
  • Expiration checks
  • Not-before validation
  • Issuer allowlists
  • Schema validation
  • Webhook verification

When Applied:

  • After presentations are validated and credentials are extracted
  • Applied to every credential in parallel
  • Runs regardless of which DCQL query the credential satisfies

Example Configuration:

{
  "vc_policies": [
    "signature",
    "expiration",
    "not-before",
    {
      "policy": "allowed-issuer",
      "allowed_issuer": ["did:example:trusted-issuer"]
    },
    {
      "policy": "schema",
      "schema": {
        "type": "object",
        "properties": {
          "credentialSubject": {
            "type": "object"
          }
        }
      }
    }
  ]
}

Default Behavior: If not specified, defaults to ["signature"] (signature verification only).

Available Policies:


3. Specific VC-Level Policies (specific_vc_policies)

Scope: Applied to credentials that satisfy specific DCQL credential queries, identified by query ID.

Purpose: Enforce credential-type-specific or query-specific requirements such as:

  • Schema validation for specific credential types
  • Issuer restrictions for specific credential queries
  • Custom validation rules for particular credential formats
  • Field-specific regex patterns

When Applied:

  • After global VC policies
  • Only to credentials that match the specified query ID
  • Allows different policies for different credential types in the same session

Example Configuration:

{
  "specific_vc_policies": {
    "identity_credential": [
      {
        "policy": "schema",
        "schema": {
          "type": "object",
          "required": ["credentialSubject"],
          "properties": {
            "credentialSubject": {
              "type": "object",
              "required": ["name", "email"]
            }
          }
        }
      },
      {
        "policy": "allowed-issuer",
        "allowed_issuer": ["did:example:identity-issuer"]
      }
    ],
    "drivers_license": [
      {
        "policy": "vical",
        "vical": "<base64-encoded-vical-data>",
        "enableDocumentTypeValidation": true,
        "enableRevocation": true
      }
    ],
    "age_verification": [
      {
        "policy": "regex",
        "path": "$.credentialSubject.age",
        "regex": "^[0-9]{1,3}$"
      }
    ]
  }
}

Available Policies:


Policy Execution Flow

The verification engine executes policies in the following order:

1. Parse vp_token → Extract presentations
   ↓
2. VP-Level Policies (vp_policies)
   - Validate presentation signatures, audience, nonce
   - Format-specific checks (SD hash, device auth, etc.)
   ↓
3. Extract credentials from validated presentations
   ↓
4. Global VC-Level Policies (vc_policies)
   - Applied to ALL credentials in parallel
   ↓
5. Specific VC-Level Policies (specific_vc_policies)
   - Applied to credentials matching specific query IDs
   ↓
6. Aggregate results and determine overall success

Key Points:

  • Policies at each level run in parallel (using coroutines)
  • If any policy fails, the overall verification may fail (depending on configuration)
  • Results are collected and aggregated into Verifier2PolicyResults
  • The overallSuccess flag requires all policies at all levels to succeed

Complete Example

Here's a complete example showing all policy levels:

{
  "dcql_query": {
    "credentials": [
      {
        "id": "identity_credential",
        "format": "jwt_vc_json",
        "claims": [...]
      },
      {
        "id": "drivers_license",
        "format": "mso_mdoc",
        "meta": {
          "doctype_value": "org.iso.18013.5.1.mDL"
        }
      }
    ]
  },
  "policies": {
    "vp_policies": {
      "jwt_vc_json": [
        "jwt_vc_json/audience-check",
        "jwt_vc_json/nonce-check",
        "jwt_vc_json/envelope_signature"
      ],
      "mso_mdoc": [
        "mso_mdoc/device-auth",
        "mso_mdoc/issuer_auth",
        "mso_mdoc/mso"
      ]
    },
    "vc_policies": [
      "signature",
      "expiration",
      "not-before",
      {
        "policy": "allowed-issuer",
        "allowed_issuer": [
          "did:example:trusted-issuer-1",
          "did:example:trusted-issuer-2"
        ]
      }
    ],
    "specific_vc_policies": {
      "identity_credential": [
        {
          "policy": "schema",
          "schema": {
            "type": "object",
            "required": ["credentialSubject"],
            "properties": {
              "credentialSubject": {
                "type": "object",
                "required": ["name", "email"]
              }
            }
          }
        },
        {
          "policy": "regex",
          "path": "$.credentialSubject.email",
          "regex": "^.+@example\.com$"
        }
      ],
      "drivers_license": [
        {
          "policy": "vical",
          "vical": "<base64-encoded-vical>",
          "enableDocumentTypeValidation": true,
          "enableRevocation": true
        }
      ]
    }
  }
}

What happens:

  1. VP Policies:
    • JWT VC JSON presentations are validated for audience, nonce, and signature
    • mdoc presentations are validated for device auth, issuer auth, and MSO validity
  2. Global VC Policies:
    • ALL credentials (both identity and drivers license) are checked for:
      • Signature validity
      • Expiration status
      • Not-before validity
      • Issuer is in the trusted list
  3. Specific VC Policies:
    • Credentials matching identity_credential query additionally checked for:
      • Schema compliance (must have credentialSubject with name and email)
      • Email format matches @example.com pattern
    • Credentials matching drivers_license query additionally checked for:
      • VICAL trust anchor validation
      • Document type validation
      • Revocation status

Policy Result Structure

Results are collected into Verifier2PolicyResults:

data class Verifier2PolicyResults(
    val vpPolicies: Map<String, Map<String, VPPolicy2.PolicyRunResult>>,
    val vcPolicies: List<CredentialPolicyResult>,
    val specificVcPolicies: Map<String, List<CredentialPolicyResult>>
) {
    val overallSuccess: Boolean =
        vpPolicies.all { it.value.all { it.value.success } } &&
        vcPolicies.all { it.success } &&
        specificVcPolicies.values.all { policies -> policies.all { it.success } }
}

The overallSuccess property requires all policies at all levels to succeed for the verification to be considered successful.


Use Cases

Use Case 1: Basic Verification

Apply only essential checks to all credentials:

{
  "vc_policies": ["signature", "expiration"]
}

Use Case 2: Format-Specific Requirements

Different policies for different credential types:

{
  "vc_policies": ["signature"],
  "specific_vc_policies": {
    "mdoc_credential": [
      {"policy": "vical", "vical": "..."}
    ],
    "jwt_credential": [
      {"policy": "schema", "schema": {...}}
    ]
  }
}

Use Case 3: Strict Verification

Comprehensive checks at all levels:

{
  "vp_policies": {...},  // All presentation checks
  "vc_policies": [
    "signature",
    "expiration",
    "not-before",
    {"policy": "allowed-issuer", "allowed_issuer": [...]}
  ],
  "specific_vc_policies": {
    "each_query": [
      {"policy": "schema", "schema": {...}}
    ]
  }
}

Configuration via API

When creating a verification session via the API (POST /verification-session/create), policies are specified in the policies field of VerificationSessionSetup:

{
  "flow_type": "cross_device",
  "core_flow": {
    "dcql_query": {...},
    "policies": {
      "vp_policies": {...},
      "vc_policies": [...],
      "specific_vc_policies": {...}
    }
  }
}

If policies are not specified, defaults are applied:

  • VP policies: Format-specific defaults (see VP-Level Policies section)
  • VC policies: ["signature"] (signature verification only)
  • Specific VC policies: {} (empty, no specific policies)
Last updated on December 3, 2025