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_tokenresponse - 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_signaturedc+sd-jwt: audience-check, nonce-check, kb-jwt_signature, sd_hash-checkmso_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
overallSuccessflag 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:
- 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
- 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
- ALL credentials (both identity and drivers license) are checked for:
- Specific VC Policies:
- Credentials matching
identity_credentialquery additionally checked for:- Schema compliance (must have credentialSubject with name and email)
- Email format matches
@example.compattern
- Credentials matching
drivers_licensequery additionally checked for:- VICAL trust anchor validation
- Document type validation
- Revocation status
- Credentials matching
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)
