---
title: "Verifier Integration"
description: "Link the Trust Registry to a Verifier2 Service to enable automatic trust verification during credential presentation. The etsi-trust-list policy matches issuer certificates — or, for issuers with no certificate, issuer…"
stack: "Enterprise Stack (commercial) — version 1.1.1"
stack_version: "1.1.1"
stack_comparison: https://docs.walt.id/community-vs-enterprise.md
canonical_url: https://docs.walt.id/enterprise-stack/services/trust-registry-service/verifier-integration
generated: 2026-10-01
---
# Verifier Integration

Link the Trust Registry to a Verifier2 Service to enable automatic trust verification during credential presentation. The `etsi-trust-list` policy matches issuer certificates — or, for issuers with no certificate, issuer public keys — against trust sources already loaded in the registry, without fetching the trust list again. A credential with no `x5c` still needs its signing key resolved first. `did:jwk` needs no network call; other DID methods and HTTPS issuer metadata do. See [Public-Key and DID-Based Issuers](#public-key-and-did-based-issuers).

## Architecture

```
┌─────────────────────────────────────────────────────────────────┐
│                     Verification Flow                            │
│                                                                  │
│  Credential  ──►  Verifier2  ──►  etsi-trust-list policy        │
│                       │                    │                     │
│                       │ dependency         │ resolves via        │
│                       ▼                    ▼                     │
│              Trust Registry Service  ◄─────┘                     │
│                       │                                          │
│                       │ queries                                  │
│                       ▼                                          │
│                   Loaded Trust Sources (TSL, LoTE)               │
└─────────────────────────────────────────────────────────────────┘
```

## Prerequisites

1. A Trust Registry Service with at least one trust source loaded (see [Setup](https://docs.walt.id/enterprise-stack/services/trust-registry-service/setup.md) and [Trust Source Management](https://docs.walt.id/enterprise-stack/services/trust-registry-service/trust-source-management.md)).
2. A Verifier2 Service in the same tenant.

## Link Trust Registry to Verifier2

Add the Trust Registry as a dependency of your Verifier2 service:

**Option: CURL**

Endpoint: `/v2/{target}/verifier-service-api/dependencies/add`

**Example Request**

```bash
curl -X 'POST' \
  'https://{orgID}.enterprise-sandbox.waltid.dev/v2/{verifier2Target}/verifier-service-api/dependencies/add' \
  -H 'accept: */*' \
  -H 'Authorization: Bearer {yourToken}' \
  -H 'Content-Type: application/json' \
  -d '{
  "dependency": "myorg.tenant1.trust-registry"
}'
```

**Path Parameters**

- `orgID`: _String_ — Your organization's Base URL prefix.
- `verifier2Target`: _String_ — The Verifier2 service path, e.g. `myorg.tenant1.verifier2`.

**Header Parameters**

- `Authorization`: _String_ — Bearer token for authentication. Format: `Bearer {yourToken}`.

**Body Parameters**

- `dependency`: _String_ — The full path to the Trust Registry service, e.g. `myorg.tenant1.trust-registry`.

**Response Codes**

- `201` — Dependency added successfully.

## Verify the Link

List the Verifier2 dependencies to confirm the Trust Registry is linked:

**Option: CURL**

**Endpoint:** `GET /v2/{verifier2Target}/verifier-service-api/dependencies/list`

##### Example Request

```bash
curl -X 'GET' \
  'https://{orgID}.enterprise-sandbox.waltid.dev/v2/{verifier2Target}/verifier-service-api/dependencies/list' \
  -H 'accept: application/json' \
  -H 'Authorization: Bearer {yourToken}'
```

**Path Parameters**

- `orgID`: _String_ — Your organization's Base URL prefix.
- `verifier2Target`: _String_ — The Verifier2 service path, e.g. `myorg.tenant1.verifier2`.

**Header Parameters**

- `Authorization`: _String_ — Bearer token for authentication. Format: `Bearer {yourToken}`.

---

##### Example Response

Returns an array of all services registered as dependencies of the Verifier2 service.

```json
[
  {
    "_id": "myorg.tenant1.trust-registry",
    "type": "trust-registry"
  }
]
```

## Use the etsi-trust-list Policy

The `etsi-trust-list` policy is a standard Verifier2 VC policy. You add it to the `vc_policies` array when creating a verification session — the same way you would add `signature` or any other policy.

The policy snippet looks like this:

```json
{
  "policy": "etsi-trust-list",
  "expectedEntityType": "PID_PROVIDER",
  "allowStaleSource": false,
  "requireAuthenticated": true
}
```

Place this inside the `policies.vc_policies` array of your session creation request body. For a complete walkthrough of creating a verification session — including the full request structure, `flow_type`, `dcql_query`, and response fields — see [Credential Verification](https://docs.walt.id/enterprise-stack/services/verifier2-service/credential-verification/vc-oid4vp.md).

**Note:**

When Verifier2 has the Trust Registry linked as a dependency (as set up above), the policy resolves certificates automatically using the pre-loaded trust sources. No additional URL or inline configuration is required.

## Certificate Chain Construction

When the presented credential's header contains an `x5c` certificate chain (always the case for mDoc COSE headers; the common case for SD-JWT/JWT VC), the policy sends the complete leaf-first chain to the linked Trust Registry. The registry uses certificates stored in loaded trust sources as independent trust anchors and performs PKIX path building.

The credential should contain:

1. the credential-signing leaf certificate;
2. any intermediate certificates required to reach the registered anchor.

Do not include the root trust anchor when the applicable profile prohibits it. [OpenID4VC HAIP 1.0, Section 6.1.1](https://openid.net/specs/openid4vc-high-assurance-interoperability-profile-1_0-final.html#section-6.1.1) states that the X.509 trust-anchor certificate MUST NOT be included in the SD-JWT VC `x5c` header. The Trust Registry must contain the anchor certificate itself, not only its SHA-256 fingerprint, so it can construct the certification path.

## Public-Key and DID-Based Issuers

Not every SD-JWT/JWT VC issuer holds an X.509 certificate. An issuer that signs with a `did:web` (or other
DID method) key typically has no `x5c` header at all - only `kid` and `iss`. ETSI TS 119 602 allows
registering such an issuer in a LoTE trust list by public key alone (see
[Public-Key-Only Entities](https://docs.walt.id/enterprise-stack/services/trust-registry-service/trust-source-management.md#public-key-only-entities)), and the
`etsi-trust-list` policy resolves trust for these issuers automatically:

1. If the credential header has no `x5c`, the policy resolves the issuer's signing public key itself -
   via DID resolution (following `iss`, matching the verification method by `kid`) or, for an HTTPS
   `iss`, JWT VC issuer metadata at its well-known endpoint. This is a network call except for
   `did:jwk`, which is self-contained.
2. The resolved public key is matched against the loaded trust list by RFC 7638 SHA-256 JWK thumbprint, the
   same way [Resolve by Public Key](https://docs.walt.id/enterprise-stack/services/trust-registry-service/trust-resolution.md#resolve-by-public-key) works when called
   directly. This match stays inside the Trust Registry.

## Policy Resolution Modes

The `etsi-trust-list` policy supports three resolution modes. Choose the one that fits your deployment:

If more than one mode is configured, precedence is remote service (`trustRegistryUrl`), inline sources (`trustLists`), then the linked Enterprise service.

### 1. Linked Service Mode (Recommended)

Uses the Trust Registry you linked in the previous step. The policy discovers and queries it automatically at verification time — no extra configuration needed.

```json
{
  "policy": "etsi-trust-list",
  "expectedEntityType": "PID_PROVIDER"
}
```

This is the recommended mode for enterprise deployments. Trust lists are pre-loaded into the Trust Registry Service, so the registry match itself makes no outbound call. A credential with no `x5c` can still require a network call to resolve the issuer key, as described in [Public-Key and DID-Based Issuers](#public-key-and-did-based-issuers).

### 2. Remote Service Mode

Queries a compatible external Trust Registry API. The policy appends `/trust-registry/resolve/certificate-chain` to `trustRegistryUrl` when the credential has an `x5c` chain, or `/trust-registry/resolve/public-key` when it doesn't (see [Public-Key and DID-Based Issuers](#public-key-and-did-based-issuers)). It does not attach an Enterprise bearer token.

```json
{
  "policy": "etsi-trust-list",
  "trustRegistryUrl": "https://trust-registry.example.com",
  "expectedEntityType": "PID_PROVIDER"
}
```

**Info:**

`trustRegistryUrl` is not an Enterprise service target URL. Use linked service mode for an Enterprise Trust Registry dependency. Remote mode requires an API that exposes `POST /trust-registry/resolve/certificate-chain` and `POST /trust-registry/resolve/public-key` with suitable network access and authentication.

### 3. Inline Mode

Fetches and processes a trust list directly at verification time, without a Trust Registry service. Suitable for testing or simple deployments where operating a dedicated Trust Registry Service is not warranted.

```json
{
  "policy": "etsi-trust-list",
  "trustLists": [
    "https://www.signatur.rtr.at/vertrauensliste.xml"
  ],
  "expectedEntityType": "PID_PROVIDER"
}
```

**Error:**

Inline Mode fetches the trust list on every verification request. This adds latency and creates a runtime dependency on the availability of the external URL. Avoid this mode in production.

With `validateSignatures: true`, inline mode verifies source signature integrity. Use `requireAuthenticated: true` together with independently configured signer certificates when the source signer must also be authorized.

## Policy Configuration Options

The following parameters are supported across all resolution modes unless noted otherwise:

| Parameter | Type | Default | Description |
|-----------|------|---------|-------------|
| `expectedEntityType` | string | `null` | Filter by entity type. Valid values: `PID_PROVIDER`, `WALLET_PROVIDER`, `ATTESTATION_PROVIDER`, `TRUST_SERVICE_PROVIDER`, `ACCESS_CERTIFICATE_PROVIDER`, `RELYING_PARTY_PROVIDER`, `OTHER`. When omitted, no entity type filter is applied. |
| `expectedServiceType` | string | `null` | Filter by service type URI. When omitted, no service type filter is applied. |
| `allowStaleSource` | boolean | `false` | When `true`, accepts `STALE_SOURCE` decisions and `TRUSTED` decisions whose source freshness is `STALE`. A `STALE_SOURCE` decision can represent an expired source, so keep this `false` for strict verification. |
| `requireAuthenticated` | boolean | `false` | When `true`, requires `AUTHENTICATED` source assurance in every freshness branch. `FAILED` assurance is always rejected. When `false`, `INTEGRITY_VERIFIED`, `UNVERIFIED`, or `UNKNOWN` may be accepted if the source was admitted by its configured policy. |
| `trustRegistryUrl` | string | — | _(Remote mode only)_ Base URL of a compatible service exposing `/trust-registry/resolve/certificate-chain`. |
| `trustLists` | array of strings | — | _(Inline mode only)_ One or more trust list URLs or raw XML/JSON/JWS values to process at verification time. |
| `validateSignatures` | boolean | `true` | _(Inline mode only)_ When `true`, verifies XMLDSig or compact-JWS signatures when present. When `false`, signature verification is skipped. |
| `trustedSourceSignerCertificates` | array of strings | `[]` | _(Inline mode only)_ PEM or Base64-DER signer certificates or trust anchors used to authenticate XMLDSig and compact-JWS sources. |

### Example Configurations

**Strict linked-service mode** — entity type enforced, stale sources rejected, and the previously loaded source must be authenticated:

```json
{
  "policy": "etsi-trust-list",
  "expectedEntityType": "PID_PROVIDER",
  "allowStaleSource": false,
  "requireAuthenticated": true
}
```

The linked Trust Registry must have admitted the source with `REQUIRE_AUTHENTICATED`; setting `requireAuthenticated` on the verification policy does not authenticate a source retroactively.

**Permissive development mode** — useful for controlled testing when trust sources are not independently authenticated:

```json
{
  "policy": "etsi-trust-list",
  "expectedEntityType": "PID_PROVIDER",
  "allowStaleSource": true,
  "requireAuthenticated": false
}
```

## Verification Result

Once a wallet has responded to the verification request and the session is complete, retrieve the session result using the [session info endpoint](https://docs.walt.id/enterprise-stack/services/verifier2-service/credential-verification/vc-oid4vp.md). The `policyResults` field contains one entry per applied policy.

For the `etsi-trust-list` policy, a successful result looks like this:

```json
{
  "policy": "etsi-trust-list",
  "success": true,
  "result": {
    "trusted": true,
    "decision": "TRUSTED",
    "matchedEntity": {
      "entityId": "entity-123",
      "entityType": "PID_PROVIDER",
      "legalName": "Example PID Provider",
      "country": "DE"
    },
    "matchedService": {
      "serviceId": "service-456",
      "serviceType": "http://uri.etsi.org/TrstSvc/Svctype/IdV",
      "status": "GRANTED"
    },
    "matchedSource": {
      "sourceId": "pid-providers",
      "sourceFamily": "LOTE",
      "format": "ETSI_TS_119_602_JSON",
      "displayName": "EU PID Providers"
    },
    "sourceFreshness": "FRESH",
    "authenticity": "AUTHENTICATED"
  }
}
```

**Result fields:**

- `trusted`: Always `true` for a successful policy result.
- `decision`: The trust resolution outcome. `TRUSTED` means the issuer was found in a valid trusted source. `STALE_SOURCE` means the source was found but is stale — only returned as a success when `allowStaleSource: true` is set.
- `matchedEntity` _(optional)_: The entity in the trust source whose certificate matched.
  - `entityId`: The entity's identifier within the trust source.
  - `entityType`: The type of the entity, e.g. `PID_PROVIDER`, `WALLET_PROVIDER`, `ATTESTATION_PROVIDER`.
  - `legalName`: The registered legal name of the entity.
  - `country` _(optional)_: The country code of the entity, when available.
- `matchedService` _(optional)_: The specific trust service entry that matched the certificate.
  - `serviceId`: The service's identifier within the trust source.
  - `serviceType`: The service type URI as defined in the trust list.
  - `status`: The service status URI as defined in the trust list.
- `matchedSource`: The trust source that produced the match.
  - `sourceId`: The ID of the trust source as registered in the Trust Registry.
  - `sourceFamily`: The trust list family, e.g. `TSL` or `LOTE`.
  - `displayName`: The human-readable name of the trust source.
- `sourceFreshness`: Freshness state of the trust source at verification time. Possible values: `FRESH`, `STALE`, `EXPIRED`, `UNKNOWN`.
- `authenticity`: Source assurance projection. Possible values: `AUTHENTICATED`, `INTEGRITY_VERIFIED`, `UNVERIFIED`, `FAILED`, or `UNKNOWN`.
- `warnings` _(optional)_: Array of warning strings, present only when the policy succeeded with caveats (e.g. stale source accepted).

## Troubleshooting Verification

- `No trust source configured`: link a Trust Registry dependency, set `trustRegistryUrl`, or provide `trustLists`.
- `JWT has no x5c certificate chain in header, and the issuer's public key could not be resolved`: the credential has no `x5c`, and the issuer's `iss` is not a resolvable DID and not an HTTPS URL serving JWT VC issuer metadata. Verify the DID document is reachable and its verification method matches the credential's `kid`, or register the issuer's certificate instead.
- `Certificate not trusted` / `NOT_TRUSTED` for a DID-based issuer: the issuer resolved successfully, but no `PublicKeyValues` entity in the loaded trust list matches its JWK thumbprint. Confirm the trust list registers the issuer's *current* signing key — see [Public-Key-Only Entities](https://docs.walt.id/enterprise-stack/services/trust-registry-service/trust-source-management.md#public-key-only-entities).
- `Trust source is not authenticated`: load the source with `REQUIRE_AUTHENTICATED` and an independently trusted signer certificate, or correct the inline signer configuration.
- `Trust source is stale or expired`: refresh the source and inspect its `nextUpdate` value. Enable `allowStaleSource` only after assessing the risk.
- `No valid path`: ensure the credential presents the leaf and required intermediates, while the Trust Registry stores the full anchor certificate.
