> For clean Markdown of any page, append .md to the page URL.
> For a complete documentation index, see https://rivet.chrisboulton.com/llms.txt.
> For AI client integration (Claude Code, Cursor, etc.), connect to the MCP server at https://rivet.chrisboulton.com/_mcp/server.

# Trusted identity and claims

> Classify nodes using certificate or JWT claims verified by the compile service.

[Facts](/language/facts) are reported by the host, so a compromised host can claim to be anything. `trusted` holds values the [compile service](/operations/compile-service) derived from the host's verified credential: its GCP identity token, mTLS client certificate, or OIDC token. Hosts can't supply or override it; the request has no field for it, and a custom fact named `trusted` is just another fact.

| Path                     | Meaning                                                   |
| ------------------------ | --------------------------------------------------------- |
| `trusted.authentication` | `mtls`, `gcp`, or `oidc`.                                 |
| `trusted.principal`      | Exact principal matched by server allow rules.            |
| `trusted.node`           | Credential-derived node identity.                         |
| `trusted.claims`         | Verified provider and certificate claims described below. |

This only compiles on the compile service, so it can't be tested locally:

```text
file "node_identity" {
  path    = "/etc/rivet-node-identity"
  content = "${trusted.authentication}:${trusted.node}"
}

# In a GCP deployment:
output "project_number" {
  type  = number
  value = trusted.claims.google.compute_engine.project_number
}
```

Claims are read like facts and keep their JSON types. A missing claim is a compile error.

## mTLS claims

```json
{
  "authentication": "mtls",
  "principal": "mtls:uri:urn:rivet:node:web-01",
  "node": "urn:rivet:node:web-01",
  "claims": {
    "subject": {"common_name": "web-01", "organization": "Example"},
    "issuer": {"common_name": "Example Rivet Node CA"},
    "subject_alt_names": {
      "uris": ["urn:rivet:node:web-01"],
      "dns_names": ["web-01.example.com"]
    },
    "extensions": {"role": "web", "environment": "production"}
  }
}
```

Subject and issuer expose available `common_name`, `organization`, `organizational_unit`, `country`, `state`, and `locality` fields. One occurrence is a string; repeated values form an array; missing fields are omitted. SAN arrays are present even when DNS names are empty. Authentication still requires exactly one Rivet node URI SAN.

Only OIDs mapped by server `authentication.trusted_extensions` appear under `claims.extensions`; missing extensions are omitted. Use `trusted.claims.extensions.role` for a configured role. The [mTLS configuration](/operations/compile-service#mtls) explains encoding, size, and CA approval requirements. Arbitrary certificate extensions are not exposed.

## GCP claims

Verified JWT fields retain their names, nesting, and JSON types:

```json
{
  "authentication": "gcp",
  "principal": "gcp:service-account:rivet-agent@example-project.iam.gserviceaccount.com",
  "node": "gcp:instance:example-project:us-central1-a:1234567890123456789",
  "claims": {
    "iss": "https://accounts.google.com",
    "aud": "https://rivet.example.com",
    "sub": "109876543210987654321",
    "azp": "109876543210987654321",
    "email": "rivet-agent@example-project.iam.gserviceaccount.com",
    "email_verified": true,
    "google": {
      "compute_engine": {
        "project_id": "example-project",
        "project_number": 123456789012,
        "zone": "us-central1-a",
        "instance_id": "1234567890123456789",
        "instance_name": "web-01",
        "instance_creation_timestamp": 1700000000,
        "instance_confidentiality": 1,
        "license_id": ["1000001", "1000002"]
      }
    }
  }
}
```

Optional provider fields are omitted when absent. Known numeric fields must be unsigned JSON numbers; `license_id` must be an array of strings. Signature, issuer, audience, lifetime, project, full VM identity, and verified-email checks run before any claims enter compilation. Use paths such as `trusted.claims.google.compute_engine.project_id` and `trusted.claims.email_verified`.

## OIDC claims

OIDC sets `authentication` to `oidc`, uses `oidc:<issuer>:<subject>` for both principal and node, and exposes the verified issuer payload under `claims`, including custom fields such as `groups` or `environment`. The configured issuer is responsible for the meaning and issuance policy of those custom fields.

For both GCP and OIDC, `iat`, `exp`, `nbf`, and `jti` remain authentication inputs but are removed from HCL-visible claims. Credential rotation alone therefore does not change desired configuration. Raw tokens and certificate bytes never enter `trusted`.

## Digests, sensitivity, and availability

Unused claims do not affect the catalog's semantic digest. Claims used in desired state or outputs do, like inventory values. Identity claims are not automatically sensitive; apply [existing sensitive policies](/language/metadata) when appropriate. The serialized trusted context is limited to 64 KiB independently of inventory.

`trusted` exists only when the compile service compiles. Direct `rivet compile`, `release compile` and `release validate`, and source-mode agents have nothing to verify, so referencing `trusted` there is a compile error. Offline runs reuse the last catalog, so they don't pick up new claims or notice revoked credentials.