# DomainLinkage and allowed domains

This page describes how the Verifier applies **W3C Domain Linkage** checks and the optional **issuer allow-list** (`issuerAllowedDomains`) during VP/VC validation.

***

## What problem this solves

* **Bind issuer DID → web origin**: Proves that an issuer controls a given HTTPS origin via W3C **Domain Linkage Credentials** (DLC) published at `/.well-known/did-configuration.json`.
* **Restrict acceptable issuers**: Lets verifiers **allow-list** issuer websites via `issuerAllowedDomains` to enforce business or compliance policies.

***

## When it runs

During **VP verification**:

1. Validate VP holder DID and VP proof.
2. For each embedded VC:
   * Validate VC proof and issuer DID Document.
   * If issuer advertises **LinkedDomains**, verify Domain Linkage for each advertised **origin**.
   * If `issuerAllowedDomains` present, enforce allow-list by **origin** intersection.
   * Check revocation/expiry/etc.

> If any VC fails its linkage or allow-list check, the VP is rejected per policy.

***

## Inputs

### Configuration surface

You can provide the allow-list at **request time** or via a **stored VP Query**:

* **Create Authorization Request** (`CreateAuthorizationRequestDto`)
  * `issuerAllowedDomains?: string[]`
* **Create VP Query** (`CreateVpQueryRequestDto`)
  * `issuerAllowedDomains?: string[]`

**Format**: canonical HTTPS URLs

* Must include `https://`
* Optional `:port` and `/path` (queries/fragments are not allowed)
* Examples: `https://issuer.example.com`, `https://issuer.example.com:8443`, `https://issuer.example.com/trusted`

**Normalization** (runtime):

* Host is case-folded
* Trailing slashes trimmed
* Duplicates removed
* **Matching is by `URL.origin`** (paths accepted in config but ignored for linkage matching per spec)

If omitted or empty → **no issuer-domain restriction** (backward-compatible).

***

## Domain Linkage (W3C) — how it works

1. **Discover linked origins**: From issuer DID Document services (e.g., `LinkedDomains`), the resolver extracts HTTPS **origins**.
2. **Fetch configuration**: For each origin, download `origin + "/.well-known/did-configuration.json"`.
3. **Validate DLCs**:
   * Check `type` includes `DomainLinkageCredential`
   * Subject `{ id: <issuer DID>, origin: <that origin> }`
   * Issuer equals the same DID
   * Proof verifies against one of the DID’s **assertionMethod** keys
   * Enforce safe limits (payload sizes, max entries, timeout)
4. **Accept origin** if any DLC for that origin validates.

> This proves control of the website by the issuer DID.

***

## Allow-list enforcement (`issuerAllowedDomains`)

* Build `allowedOrigins = unique(origin(url) for url in issuerAllowedDomains)`.
* For each VC issuer:
  * Compute `linkedOrigins` (validated via Domain Linkage).
    * If issuer has **no LinkedDomains**, `linkedOrigins` may be empty.
  * **Decision**:
    * If allow-list is **not** provided → skip restriction.
    * If allow-list **is** provided:
      * If issuer advertises LinkedDomains → require `intersection(allowedOrigins, linkedOrigins) ≠ ∅`.
      * If issuer does **not** advertise LinkedDomains:
        * **did:web**: treat the DID’s web **origin** as the issuer origin and compare to `allowedOrigins`.
        * Other methods (e.g., `did:empe`) with no LinkedDomains → **reject** (cannot bind DID to a web origin) unless your policy explicitly allows such issuers without origins.

> Paths in `issuerAllowedDomains` are accepted for configuration convenience but **do not** participate in the origin match.

***

## did:web specifics

* **Domain Linkage** is not required for `did:web` because the DID is inherently bound to a domain.
* For allow-list:
  * Extract the **origin** from the DID URL (e.g., `did:web:example.com` → `https://example.com`).
  * Compare against `allowedOrigins`. If no match → reject.

***

## Practical examples

**1) Stored VP Query with allow-list**

```json
{
  "query": [ { "fields": [ { "path": ["$.type"], "filter": { "type": "array", "contains": { "const": "IdentityCredential" } } } ] } ],
  "issuerAllowedDomains": [
    "https://issuer.example.com",
    "https://partners.example.org:8443/trusted"
  ]
}
```

* During verification:
  * Issuer’s LinkedDomains are DLC-validated.
  * Must match `https://issuer.example.com` or `https://partners.example.org:8443` by **origin**.

**2) did:web issuer**

* `did:web:university.edu`
* No LinkedDomains needed. Verify VC; then ensure origin `https://university.edu` is in `issuerAllowedDomains` (if provided).

**3) did:empe issuer without LinkedDomains**

* If `issuerAllowedDomains` is set → **reject** (no origin to compare), unless you disable the policy or the issuer adds LinkedDomains+DLC.

***


---

# Agent Instructions: 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:

```
GET https://docs.empe.io/develop/verifier/domain-linkage.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
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.
