> For the complete documentation index, see [llms.txt](https://docs.empe.io/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.empe.io/develop/verifier.md).

# Verifier

The Verifier is a core component of the EVDI (Empeiria's End-to-End Verifiable Data Infrastructure) ecosystem. It requests and validates Verifiable Presentations (VPs) from wallets and checks the Verifiable Credentials (VCs) inside them, using the **OpenID4VP** protocol over a standards-based HTTP API. Acting as the relying party between wallets and your application, the Verifier lets you build credential-based access control and passwordless login flows on top of cryptographically verifiable claims.

**Key Highlights:**

* **Standards Alignment** Implements **OpenID4VP** for presentation requests and verifies W3C-aligned Verifiable Credentials in two formats: **SD-JWT VC** (`dc+sd-jwt`), which honors selective disclosure so holders reveal only the claims you ask for, and **JWT-VC-JSON** (`jwt_vc_json`). Three OpenID4VP draft versions are supported: `v1` (default), `v1.draft21`, and `v1.draft24`.
* **Flexible Credential Queries** Request exactly the credentials and claims you need using either a **DCQL** query or a **DIF Presentation Exchange v2** definition. Each authorization request must carry exactly one of the two.
* **Multiple Response Modes** Authorization requests can use `direct_post`, `direct_post.jwt` (default), or the Digital Credentials API modes `dc_api` and `dc_api.jwt`, so you can integrate with both redirect-based wallets and in-browser credential APIs.
* **Real-Time Feedback** Each request creates a **verification session** whose state you can poll, or subscribe to over **Server-Sent Events (SSE)** to receive live updates as the wallet responds and verification completes.
* **Standalone Credential Verification** Beyond the full presentation flow, a direct endpoint verifies a single compact credential string (SD-JWT or JWT-VC) and returns its decoded claims — useful for server-to-server checks and testing.
* **Decentralized Identifiers** Issuer and holder DIDs using **`did:web`** and **`did:key`** (Ed25519) are supported today; the service serves its own `did:web` documents over HTTPS (see [Terminology and Concepts](/develop/verifier/terminology-and-concepts.md) for `did:empe`).
* **Security and Access Controls** Verifier endpoints require a valid **OIDC JWT Bearer token** (`Authorization: Bearer <token>`), validated against a JWKS endpoint. HTTPS is required in production.

***

## Verifying a Presentation

The typical verifier workflow is: create an authorization request that describes the credentials you need, hand the request URI (or its QR code) to a wallet, then track the verification session until it completes. All requests below require a valid `Authorization: Bearer <token>` header.

### 1. Create an Authorization Request

**`POST /verifiers/:verifierId/authorization-requests`**

**Request Body:**

```json
{
  "dcqlQuery": {
    "credentials": [
      {
        "id": "employee_badge",
        "format": "dc+sd-jwt",
        "meta": { "vct_values": ["https://issuer.example.com/vct/employee-badge"] },
        "claims": [
          { "path": ["employee_id"] },
          { "path": ["department"] }
        ]
      }
    ]
  },
  "responseMode": "direct_post.jwt",
  "version": "v1"
}
```

* **dcqlQuery**: A DCQL query describing the requested credentials and claims. Provide exactly one of `dcqlQuery` or `presentationDefinition`.
* **presentationDefinition**: A DIF Presentation Exchange v2 definition, as an alternative to `dcqlQuery`. Requires `version` to be `v1.draft21` or `v1.draft24`.
* **responseMode**: One of `direct_post`, `direct_post.jwt`, `dc_api`, or `dc_api.jwt`. Defaults to `direct_post.jwt`.
* **version**: OpenID4VP draft version — `v1`, `v1.draft21`, or `v1.draft24`. Defaults to `v1`, which supports only `dcqlQuery`; use `v1.draft21` or `v1.draft24` with `presentationDefinition` (and note that `dcqlQuery` cannot be combined with `v1.draft21`).
* **signingDid**: Optional DID used to sign the authorization request. If omitted, the `verifierId` path parameter must already be a DID.
* **expectedOrigins**: Optional list of expected origins for Digital Credentials API flows.
* **authorizationResponseRedirectUri**, **transactionData**, **verifierInfo**: Optional advanced parameters included in the request.

**Response Body:**

```json
{
  "authorizationRequestUri": "openid4vp://?request_uri=...",
  "verificationSessionId": "18b760b1-4ab8-4d38-9d42-6b4c25a4d2e0",
  "authorizationRequestId": "1b8a6a8b-2ac1-4f0b-9d9c-6b9c859b1af2",
  "expiresAt": "2024-08-09T12:34:56.789Z"
}
```

* **authorizationRequestUri**: The `openid4vp://` URI the wallet opens to respond to the request.
* **verificationSessionId**: Identifier used to track and subscribe to the verification session.
* **authorizationRequestId**: Identifier of the hosted request, when applicable.
* **expiresAt**: When the request expires, in ISO format.

To obtain a scannable QR code instead of JSON, call **`POST /verifiers/:verifierId/authorization-requests/qr-code`** with the same body. It returns a **PNG image** and exposes the request details in the `X-Authorization-Request-Uri`, `X-Verification-Session-Id`, and `X-Authorization-Request-Id` response headers.

### 2. Track the Verification Session

**`GET /verification-sessions/:sessionId`**

Returns the current session state and request details.

**Response Body:**

```json
{
  "id": "18b760b1-4ab8-4d38-9d42-6b4c25a4d2e0",
  "verifierId": "verifier-empe",
  "state": "RequestCreated",
  "authorizationRequestId": "1b8a6a8b-2ac1-4f0b-9d9c-6b9c859b1af2",
  "authorizationRequestUri": "openid4vp://?request_uri=...",
  "expiresAt": "2024-08-09T12:34:56.789Z"
}
```

* **state**: The session lifecycle state, which advances as the wallet responds (for example `RequestCreated`).
* **errorMessage**: Present when verification fails, describing the last error observed.

### 3. Subscribe to Live Updates (SSE)

**`GET /verification-sessions/:sessionId/events`**

Opens a **Server-Sent Events** stream for the session. The stream emits a `session` event carrying the session object (the same shape as the read above) immediately on subscribe — reflecting the session's current state — and again each time the state changes, plus a `ping` heartbeat every 15 seconds to keep the connection alive. Use it to update your UI in real time while the wallet presents its credentials.

***

## Standalone Credential Verification

To verify a single credential string directly — without a presentation flow — post its compact serialized form.

**`POST /credentials/verify`**

**Request Body:**

```json
{
  "credential": "eyJhbGciOiJFZERTQSJ9.eyJ2Y3QiOi...~WyJhIiwiZW1wbG95ZWVfaWQiXQ~"
}
```

* **credential**: A compact JWT or SD-JWT credential string.

**Response Body (valid):**

```json
{
  "isValid": true,
  "format": "dc+sd-jwt",
  "payload": { "vct": "https://issuer.example.com/vct/employee-badge", "employee_id": "EMP-001" },
  "prettyClaims": { "vct": "https://issuer.example.com/vct/employee-badge", "employee_id": "EMP-001", "full_name": "Ada Lovelace", "department": "Engineering" }
}
```

* **isValid**: Whether the credential passed verification.
* **format**: The detected credential format. A verified SD-JWT credential returns `"dc+sd-jwt"`; a verified JWT-VC returns `"jwt_vc"`.
* **payload**: The decoded credential payload.
* **prettyClaims**: For SD-JWT credentials, all disclosed claims merged into a single object.

**Response Body (invalid):**

```json
{
  "isValid": false,
  "error": "<reason the credential failed verification>"
}
```

***

## Authentication

All Verifier endpoints are protected. Requests must include a valid OIDC-issued JWT in the `Authorization` header:

```bash
Authorization: Bearer <token>
```

Tokens are validated against a JWKS endpoint (`OIDC_JWKS_URL`). See [Authentication](/develop/verifier/authentication.md) for token validation details and the local-development bypass.


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter, and the optional `goal` query parameter:

```
GET https://docs.empe.io/develop/verifier.md?ask=<question>&goal=<endgoal>
```

`ask` is the immediate question: it should be specific, self-contained, and written in natural language.
`goal` is optional and describes the broader end goal you are ultimately trying to accomplish on behalf of the user. GitBook uses it to tailor the answer towards what is most useful for that goal.

The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
