AXIAM PHP SDK

CimdPolicy
in package
implements JsonSerializable

FinalYes

Whether, and on what terms, a `client_id` that is a URL is resolved by fetching the document it names (T21.5, `draft-ietf-oauth-client-id-metadata-document`). # Why this is one nested policy rather than nine fields Every field here is a term of a single decision — *do we fetch a stranger's URL and make a client out of what comes back* — and none of them means anything without [`Self::enabled`]. A tenant that states a CIMD posture states all of it; a tenant that states none inherits its organization's whole posture rather than half of one, which is the only merge that cannot produce a combination neither party wrote. # The two fields that can widen, and the seven that cannot [`Self::enabled`] and [`Self::allow_http`] are **ordered**: a tenant may turn either off but never on, exactly as `dynamic_registration` may only move down its ladder. Everything else names *this tenant's* domains or *this tenant's* bounds, and there is no sense in which one tenant's list of trusted publishers is stricter than another's — the same argument [`OidcPolicy`] already makes for `dcr_allowed_redirect_hosts`. # Every bound here is a security control [`Self::max_metadata_bytes`], [`Self::min_cache_secs`] and [`Self::max_cache_secs`] are not tuning knobs. They are, respectively, the ceiling on a read from an attacker-chosen URL, the floor under how often that read may be repeated, and the ceiling on how long its result may be trusted. Each is clamped again in code against the three constants above, so a settings row written by hand cannot lift them.

Every property is optional: one you leave unset is omitted from the wire request entirely rather than sent as null (§27.4 rule 5).

Table of Contents

Interfaces

JsonSerializable

Properties

$allowHttp  : bool|null
$confidentialOnly  : bool|null
$enabled  : bool|null
$maxCacheSecs  : int|null
$maxMetadataBytes  : int|null
$minCacheSecs  : int|null
$restrictSameDomain  : bool|null
$trustedClientIdDomains  : array<string|int, mixed>|null
$trustedRedirectDomains  : array<string|int, mixed>|null

Methods

__construct()  : mixed
Constructs a CimdPolicy.
fromArray()  : self
Rebuilds a CimdPolicy from one decoded JSON object.
jsonSerialize()  : array<string, mixed>
Renders this object for `json_encode()`.
toArray()  : array<string, mixed>
Renders this object back to its wire form.

Properties

$allowHttp read-only

public bool|null $allowHttp = null

$confidentialOnly read-only

public bool|null $confidentialOnly = null

$enabled read-only

public bool|null $enabled = null

$maxCacheSecs read-only

public int|null $maxCacheSecs = null

$maxMetadataBytes read-only

public int|null $maxMetadataBytes = null

$minCacheSecs read-only

public int|null $minCacheSecs = null

$restrictSameDomain read-only

public bool|null $restrictSameDomain = null

$trustedClientIdDomains read-only

public array<string|int, mixed>|null $trustedClientIdDomains = null

$trustedRedirectDomains read-only

public array<string|int, mixed>|null $trustedRedirectDomains = null

Methods

__construct()

Constructs a CimdPolicy.

public __construct([bool|null $allowHttp = null ][, bool|null $confidentialOnly = null ][, bool|null $enabled = null ][, int|null $maxCacheSecs = null ][, int|null $maxMetadataBytes = null ][, int|null $minCacheSecs = null ][, bool|null $restrictSameDomain = null ][, array<int, string>|null $trustedClientIdDomains = null ][, array<int, string>|null $trustedRedirectDomains = null ]) : mixed
Parameters
$allowHttp : bool|null = null

Permit an http:// client_id and an http:// fetch. Development only, and it does more than its name says.* AXIAM's shared SSRF guard couples the scheme rule to the address rule — the same seam that lets an integration test point a fetch at a loopback mock server — so a tenant that allows http also allows the first hop to resolve to a private address. Redirect hops are validated strictly whatever this says, and a public deployment that sets it has removed the control that makes 169.254.169.254 unreachable. (optional)

$confidentialOnly : bool|null = null

Refuse a document whose token_endpoint_auth_method is none. Off by default, because none is what every MCP desktop client is. A tenant that turns it on accepts only private_key_jwt documents, which is the posture for a deployment whose CIMD clients are servers rather than desktops. (optional)

$enabled : bool|null = null

Off unless somebody turns it on (I1). With this false, a URL-shaped client_id is exactly today's unknown client: nothing is fetched, nothing is materialised, and the ordinary repository lookup answers as it always has. (optional)

$maxCacheSecs : int|null = null

The ceiling on a document's cache lifetime, in seconds. Clamped to [CIMD_MAX_CACHE_CEILING_SECS]. (optional)

$maxMetadataBytes : int|null = null

The hard cap on how many bytes of a document are read, before it is parsed. Clamped to [CIMD_MAX_METADATA_BYTES_CEILING]. (optional)

$minCacheSecs : int|null = null

The floor under a document's cache lifetime, in seconds. Clamped to [CIMD_MIN_CACHE_FLOOR_SECS]. (optional)

$restrictSameDomain : bool|null = null

Require every redirect_uris host in the document to equal the host of the client_id URL itself. On by default, because the document says who the client is and a redirect to somewhere else is the one thing a stolen or mirrored document would want to change. It is turned off for the desktop MCP clients, whose callbacks are on loopback and therefore can never share a host with a https:// client_id; docs/admin/client-id-metadata-documents.md says so and says why. (optional)

$trustedClientIdDomains : array<int, string>|null = null

The hosts whose documents this tenant will fetch at all, as globs (mcp.example.com, or *.example.com for every host under one domain). An empty list resolves nothing, and enabling CIMD while it is empty is refused — see [validate_cimd_policy]. That is a deliberate departure from "a URL is a client identifier, so any URL will do": the fetch is triggered by an unauthenticated request naming the URL, so an unrestricted list is a request-forgery primitive offered to strangers, bounded only by the SSRF guard's address rules. Naming the publishers a tenant actually fronts costs one settings field and removes the class. * is refused here, and so is a wildcard over a whole top-level domain (*.com): both are the posture the empty list is refused for, spelled differently, and a control with no second control behind it cannot have a one-character bypass and still be the control. It is a floor and not a public-suffix check — *.github.io passes, and trusting shared hosting stays the operator's decision, bounded by the per-tenant quota rather than by this field. * remains valid in [CimdPolicy::trusted_redirect_domains], whose entries are not fetch targets. (optional)

$trustedRedirectDomains : array<int, string>|null = null

The hosts a document's redirect_uris may point at, as globs. The loopback hosts (127.0.0.1, [::1], localhost) are always allowed, because RFC 8252 §7.3 is how every desktop MCP client receives its callback — so an empty list is not a refusal of everything, it is "loopback only", which is exactly the Claude Code and VS Code profile. (optional)

fromArray()

Rebuilds a CimdPolicy from one decoded JSON object.

public static fromArray(array<string, mixed> $data) : self
Parameters
$data : array<string, mixed>

The raw wire object.

Return values
self

jsonSerialize()

Renders this object for `json_encode()`.

public jsonSerialize() : array<string, mixed>

Any Sensitive it carries stays WRAPPED here, so a log line or a json_encode($model) in application code prints [SENSITIVE]. The one place a secret is revealed is ManagementTransport, on the way to the wire and nowhere else (§27.5).

Return values
array<string, mixed>

toArray()

Renders this object back to its wire form.

public toArray() : array<string, mixed>

§27.4 rule 5: a null property is OMITTED, not emitted as null. On a sparse update those two say opposite things — "leave this alone" versus "set this to nothing" — and only omission means the first.

Return values
array<string, mixed>
On this page

Search results