auth.evidence/v1alpha1
Rendered from contracts/auth/evidence/v1alpha1/semantics.md by connectors-docs; the source owns every rule on this page.
- Status: proposed, not implemented.
- Family: auth. Sibling documents: connection, profile, acquisition, custody, capability.
- Recorded: 2026-09-08.
1. Identity
| Field | Value |
|---|---|
| Contract | auth.evidence/v1alpha1 |
| Checks | custody_reachable, credential_present, credential_valid, identity_check, scope_check, permission_check, verify_operation |
| Nature | value-free answers to "is this connection ready and is this invocation authorized on the provider side", collected without side effects and without widening credentials |
More columns: swipe horizontally, or focus the table and use the arrow keys.
Discovery, readiness, authentication, authorization, and execution are separate facts (docs/design.md:161). Readiness has layers: process alive, infrastructure ready, provider access valid, selected resource callable, active session healthy (docs/design.md:965). Readiness checks must have no undeclared external effect and must not resolve credentials merely to list static metadata (docs/design.md:965).
3. Types
{
"connection": "conn_…",
"collected_unix_ms": 0,
"checks": [
{ "check": "custody_reachable", "result": "ok" },
{ "check": "credential_present", "result": "ok" },
{ "check": "credential_valid", "result": "ok", "expires_unix_ms": 0, "source": "cached_token_metadata" },
{ "check": "identity_check", "result": "ok", "external_identity": "opaque" },
{ "check": "scope_check", "result": "insufficient", "missing": ["required_scope"] },
{ "check": "permission_check", "result": "denied", "subject": "declared exact target" },
{ "check": "verify_operation", "result": "not_run" }
],
"state": "ready"
}
This JSON is an illustrative public projection: the missing write grant and denied target belong to particular operations, while the connection baseline is assumed valid. They do not reduce the whole connection to insufficient_scope. A concrete payload binds each operation check to its declared exact subject and reports only admitted safe details. This JSON is the public projection. It omits credential generation IDs, snapshot handles and secret-store versions; none is a public evidence identifier. Host-private evidence additionally binds the captured generation, instance, connection, auth profile and provider authority, and records each check's source, collection time, validity deadline and exact subject where applicable. collected_unix_ms never replaces those per-check deadlines.
Results: ok, missing, invalid, insufficient, denied, unavailable, uncertain, not_run. state is the global connection viability reduction in connection §4.1, using only applicable baseline checks and administrative facts. Evidence alone does not override terminal revocation or disablement.
Operation-time predicate (host-internal):
admit(connection, operation, input, captured_generation)
-> Admitted(generation_bound_pin, evidence_snapshot) | Refused(reason)
dispatch(admitted_pin, request) -> Dispatched | Refused(reason)
4. Rules
- Value freedom: no check returns or logs credential bytes, secret references, or provider URLs of private deployments.
- Effect classes per check:
| Check | External effect | Credential resolved |
|---|---|---|
custody_reachable | none | no (existence and reachability only) |
credential_present | none | no (metadata) |
credential_valid | none by default: uses stored expiry and last-known validity; a provider introspection call is a separately admitted profile | no unless introspection is enabled |
identity_check | a declared provider identity read during admitted acquisition, activation or explicit revalidation/repair; same-account refresh may use the narrowly defined lineage rule below | yes, for the exact captured generation |
scope_check | none: compares granted scopes recorded at acquisition with the operation's requires_auth | no |
permission_check | at most one provider authorization query per uncached exact target, within the admitted shared budget in §4.4; otherwise not_run | yes for the independently admitted checking connection |
verify_operation | the designated read, only when explicitly invoked by an operator or acquisition completion | yes |
More columns: swipe horizontally, or focus the table and use the arrow keys.
- Description and dispatch use the same two reductions for the same question: connection-wide viability, then exact-operation eligibility. Description reports global viability under its observation/validity bounds; invocation freshly evaluates its own scope, permissions, verification and authority, then the F05 dispatch fence. An unrelated operation's failed or stale check never poisons global viability.
collected_unix_msis not a per-check expiry or authorization lease. - Provider authorization and SaaS authorization are both required and separately reported: a provider
permission_check: okdoes not admit a caller the host's policy refuses, and vice versa (docs/design.md:381). - Readiness is not authority: an ok baseline does not itself permit an operation. Stale/unknown/not_run baseline validation yields pending (positive invalidity or consumed refresh yields reauthorization_required); unavailable custody and parent facts use their own states. Stale operation-only scope/permission/verification refuses only affected requests under connection §4.1. Not-required checks may remain not_run and supply no authority.
- Stale evidence: each required check must meet its own freshness bound at admission and dispatch. Age-valid evidence for another generation or binding is unusable. Re-collection must itself be permitted by the check's declared effect and admission rules; otherwise refuse under the applicable reduction: stale baseline validation gives pending/connection_not_ready, stale required permission gives unavailable for that operation, and stale operation verification gives connection_not_ready without changing global state. Staleness alone is not positive credential invalidity and never authorizes an implicit probe.
4.1 Credential generation and identity
The material-generation rules in §§4.1–4.3 apply to credential-bearing capabilities. Explicit anonymous and parent-route child profiles use profile §4.2: no child credential/identity/custody checks, no invented generation or account. They require a current admitted configuration/route binding and applicable verification instead. The parent retains its own F05 credential-generation/evidence fence; a child's admitted route is not a substitute for it. This is an explicit applicability branch, never a response to missing required material. Host-internal admit/dispatch above selects the appropriate binding; CredentialGeneration and EvidenceSnapshot continue to mean material-bearing evidence only.
A credential generation is a host-private, immutable capture of the material that a capability will actually use. Its host-issued opaque ID is distinct from a connection ref, configuration/descriptor revision, filename, exec command, or secret-store version. New material produces a new generation, even for the same account. An unchanged path or revision is never proof of unchanged material. A fresh process must either recover the same verifiable immutable snapshot or capture and validate a new generation; it cannot infer continuity from the path.
Evidence binds to that generation and to (instance, connection, auth profile, provider authority). Expected identity at capture is intent, not validation. Successful identity evidence establishes the observed (kind, stable subject) within that provider authority and requires it to equal the intended connection identity. A display name, token prefix, certificate filename or config revision does not establish that equality. If the profile cannot establish identity by its declared validation mechanism, the candidate remains unvalidated.
The rule covers bearer/basic/signing material, coherent client certificate and key snapshots, and the material returned by one exec-plugin run. Validating an exec result and running the helper again at dispatch would create an unvalidated substitution. Private generation IDs and any internal equality information must stay out of public metadata, errors and logs.
Configured replacement and repair must preserve the established identity. An inactive independent repair candidate with a different subject, kind, provider authority or binding is rejected as identity_mismatch (or a safe binding refusal) without replacing or poisoning a still-valid active generation. Its prior state remains subject to independently current expiry, revocation and consumed refresh. Detected substitution of the currently used material blocks dispatch pending validation; a proved identity/binding mismatch there gives connection_not_ready and reauthorization_required, with private identity_changed/binding_changed reason. Neither case permits publishing the mismatched candidate. An explicitly admitted reassignment is a distinct management action that must invalidate old admissions, evidence, cursors and sessions before admitting the new binding. This profile provides no implicit reassignment through file overwrite or refresh; where no reassignment flow is declared, refuse it.
4.2 Admission, validation and dispatch
- Host policy first admits access to the selected connection and the local capture/credential use required by the declared operation.
connections.list, descriptor fetch andconnections.describedo not capture or validate material. - Capture or acquire a handle to immutable material. Match evidence to that exact generation and binding. A detected replacement blocks pending and new dispatches until validation succeeds. Do not copy an old snapshot merely because its time bound has not expired.
- Initial activation and replacement validation use the auth profile's explicitly declared and separately admitted validation step, with its own effect and deadline budget. An ordinary business invocation permits no implicit identity read of new or changed material. One exception recollects, never validates anew: when only the time bound of the evidence for the unchanged retained custody version lapsed (or would lapse before the read could use it, as the host's own policy states), and that version is neither known invalid nor expired, a host may run the same admitted validation step once over a fresh capture of that version before admitting the read, exactly as an explicit revalidation would (the local CLI does, cli semantics); the business dispatch then needs the recollected, current evidence. If the needed step is not available or not admitted, refuse the business invocation and require activation/revalidation; an
okcached identity for old material is no fallback. An exec helper and its identity validation are subject to the same rule. - Required checks, host authorization and provider permission checks must all apply to this request and generation. For example, an SSAR result binds the exact verb, group, version, resource, namespace and any name/subresource being authorized. Capture a transient
DispatchAdmissionand pin the validated material; the pin conveys no authority beyond this admitted use. - At the dispatch boundary, atomically order the final check with connection revocation, replacement detection and new-generation publication. The selected generation must still be current, the binding and host authorization valid, and every required check unexpired. Known credential revocation, expiry, loss of the snapshot, or an authorized rotating refresh that is still unresolved refuses even a pinned admission. The last case reports
credential_valid: uncertainand the existingconnection_not_readyrefusal; it cannot assume the provider left old material usable. The transport must use the pinned bytes/key handle, never re-read the mutable path or re-run an exec helper.
Refresh exclusion also covers aliases or duplicate captures of the same rotating credential set; a fresh generation UUID is not independent authority to refresh or dispatch possibly consumed material.
For this first profile, successful refresh/replacement publication cuts off all pending old-generation admissions. A new request needs a new admission using the newly published generation and evidence; no old pin survives the publication boundary. Before that boundary a source file changing cannot silently change a pin's bytes: it may use its original validated material only while the host still considers that generation current and usable. Once replacement is detected, dispatch blocks as above. A request that already crossed the dispatch boundary may already have an external effect; publication does not undo that effect or authorize a retry.
A host unable to pin material and enforce these checks must refuse. Revalidation is a new admitted decision over a fresh capture of the selected immutable generation, never mutation of an old admission. Recollecting evidence from an unchanged retained custody version preserves that generation; changed material requires a new generation and the replacement rules. Authority, snapshot liveness and the atomic dispatch/publication ordering are runtime obligations; the ESS model records the decision shape without executing them.
4.3 Which evidence can cross a generation change
Every change creates a new evidence value. A check may be transferred only as this table allows; copied checks retain their original collection time and validity deadline, and the new value records their source generation. Transfer cannot turn not_run, denied, uncertain or expired evidence into success.
| Check | Same-identity refresh with validated lineage | Configured replacement, repair or reassignment |
|---|---|---|
custody_reachable | may retain within its original bound if the custody binding is unchanged; says nothing about the credential | same infrastructure-only rule |
credential_present | establish for the new immutable snapshot | establish for the new snapshot |
credential_valid | recompute from the new auth result and expiry; never inherit the old token's validity | establish for the new material by the declared validation mechanism |
identity_check | may retain only if the provider auth profile explicitly proves the refresh lineage preserves the same stable identity and authority; preserve age/deadline and source generation; otherwise perform admitted identity validation or refuse | validate the observed identity of the new capture; old identity evidence is not reusable |
scope_check | recompute from grants established for the new generation, including narrowing; omitted grants require a profile-defined proof of preservation or refusal | recompute against the newly established grants |
permission_check | invalidate; collect anew for the exact operation/target and new generation where supported | invalidate; same rule |
verify_operation | invalidate; keep not_run until explicitly admitted verification is performed, and refuse operations whose profile requires it | same rule |
More columns: swipe horizontally, or focus the table and use the arrow keys.
A refresh response containing the expected identity label alone is not a lineage proof. The provider auth implementation must establish that the validated refresh exchange is for the previously bound account under its declared profile. Generic refresh coordination cannot assert that provider fact. Neither retained identity nor wider new grants enlarge the caller's host permissions. Refresh publication and its revocation fence are specified by acquisition.
4.4 Exact authorization targets and fan-out budget (F08)
After host admission and configuration checks, build the complete bounded set of exact authorization targets from the declared operation and selected input. The adapter owns its typed target codec, canonical equality/order and scope interpretation. Deduplicate within the same checking binding. An empty required multi-target selection is invalid_input; omitted selectors may expand only under explicitly bounded configured selection. A collection permission never implies a different named-resource or subresource permission.
The Kubernetes binding defines the concrete tuple, namespace modes and auth-validation transport for its profile. This is an adapter index link, not a shared provider dependency.
Target equality additionally includes checking instance, connection/profile, provider authority, immutable credential generation, current binding/configuration revision and host admission scope. Mediated checks include the parent checking binding and fixed route/observation revision. A public target description is not the private cache key. Reuse requires unchanged bindings and unexpired evidence at both admission and dispatch: at most 300 s for reads, 60 s for mutation authorization, or the smaller provider/profile deadline. Revocation, replacement, policy withdrawal and invalidation win over age. Permission evidence never crosses a generation change. Denied evidence obeys the same bounds and never becomes success; caching cannot replace current host authorization.
At most 64 distinct targets and 64 authorization calls are admitted per business invocation, at most one call per uncached target and four concurrent checks. Smaller deployment/operation ceilings, including zero-call cache-only, are allowed. Cached targets count toward the target ceiling. Reserve the entire missing-evidence budget before any check: target overflow is invalid_input; insufficient remaining calls are unavailable; neither sends. Every attempted call consumes a slot even on timeout or ambiguity. Concurrency includes nested work. Stop scheduling on failure/deadline and cancel or await in-flight calls without issuing more. Pagination, parent forwarding and checks share the original business invocation's provider budget/deadline. No automatic retry, redirect, nested check or undeclared identity/verification probe is granted.
All required checks finish before the first business resource request. Only a well-formed definite allow authorizes. Missing/malformed/contradictory status and provider evaluation errors are unavailable. Unknown, not_run, stale, timed-out or unavailable required evidence refuses with zero business reads; completed checks may remain cached under their original bounds. Budget exhaustion cannot return a successful checked prefix. An explicitly declared multi-target profile may skip definitively denied targets while reporting truthful authorization coverage; all denied is forbidden. Single-target reads and mutations refuse denial. A mediated permission denial uses route_refused. If evidence expires or is invalidated before a later dispatch, discard any partial payload and return the applicable refusal; earlier resource reads are not undone. No unchecked request or implicit extra check is permitted.
The selected multi-target payload declares closed
authorization: {complete, targets: [{target, result}]}, with allowed/denied
results and the adapter's closed safe target schema. Every distinct requested
target appears once in canonical order, at most 64 entries with each textual
coordinate at most 256 UTF-8 bytes or its smaller native limit. Coverage and items
must fit the result byte bound; otherwise refuse unavailable. Any denial sets
authorization.complete and overall complete false. Allowed empty collections are
distinct from denial. Cursors bind the exact target set and coverage observation
plus normal authority/configuration fences; a change yields stale_cursor and
requires a fresh read. No cursor exists solely to retry denial. Readers lacking
the declared coverage cannot advertise this partial-read profile.
Authorization coverage does not prove provider exhaustion or disappearance. Resource coverage governs comparable absence and terminal withdrawal. Coverage exposes only admitted target coordinates, never credential generations or hidden route locators.
An auth-validation request outside the business capability's methods needs its own explicitly admitted, fixed-endpoint/body, bounded checking capability. Its evaluation counts as provider work; it grants no arbitrary business mutation. Exact native request/response interpretation and a supporting implementation are advertisement prerequisites.
4.5 Retained scope and expiry observations
EvidenceSnapshot may retain granted_scopes and credential_expires_at for its
exact captured generation. They supply the already-required scope and expiry
checks after owner restart; neither introduces a credential, a separate evidence
owner, nor another publication boundary. Native validation interprets provider
responses and any scope implications. The host retains that bounded observation
under the same binding, profile and generation fences as the snapshot.
Absent scopes mean unknown; an explicitly present empty set means a known empty
set. At most 64 distinct nonempty strings of at most 256 UTF-8 bytes are retained.
They are exact native-profile values, never a host-wide provider vocabulary or
permission grant. A scope membership check can use them only while the applicable
generation-bound scope_check remains current and successful. Operation-specific
permission and receiver policy remain separately required. Scope observation
cannot extend its check's deadline, cross a generation change implicitly, or
turn a missing/failed check into positive evidence.
Known credential expiry is an immediate cutoff at now >= credential_expires_at,
including when a cached positive check would otherwise remain fresh. Absence
does not establish that material never expires. The native profile must have
positively validated its expiry semantics before publication. The snapshot still
expires at its ordinary check deadlines. These optional private carriers are
additive; older snapshots with no scope observation cannot infer grants, and no
new public service or diagnostic field is selected by their ESS presence.
5. Limits
| Concern | Rule |
|---|---|
| Freshness bound | first-profile default 300 s for cached evidence; mutations require ≤ 60 s or re-collection |
| Authorization targets / provider calls per business invocation | ≤64 distinct targets / ≤64 calls, at most one per uncached target; lower configured bounds allowed, no retries; §4.4 defines preflight refusal and truthful denied-target coverage |
| Deadline | evidence collection shares the provider deadline; timeout → unavailable, never ok |
More columns: swipe horizontally, or focus the table and use the arrow keys.
6. Conformance scenarios
-
Describe a connection with a fake custody outage →
custody_reachable: unavailable, statecustody_unavailable; fake provider sees zero requests. -
Descriptor fetch and
connections.listnever resolve a credential (fake custody records reads → zero). -
Granted scopes lack
write:jira-work→ mutation refused withinsufficient_scope, no dispatch; a read requiringread:jira-workproceeds. -
Kubernetes fake denies SSAR for namespace
b→ list of[a, b]returnsaitems and reportsbas denied. -
Two namespaces × two resource kinds → four exact targets; fresh cached evidence saves calls, never target slots.
-
65 targets, or missing-evidence calls exceeding the admitted budget → preflight refusal; zero authorization and business requests, no successful truncated prefix.
-
One SSAR times out after another succeeds → unavailable, zero business requests; no retry or success-shaped coverage.
-
All target permissions denied → forbidden; an allowed namespace with no items remains a distinct complete empty result.
-
Expired stored token metadata →
credential_valid: invalid→ statereauthorization_required; theverify_operationis not run automatically. -
Provider
permission_checkok but receiver grant policy refuses →not_granted, no dispatch; separate adapter/connection/resource restrictions useforbidden. -
Replace account A material with account B material at the same configured path and revision → no business dispatch; separately admitted validation discovers the identity mismatch and refuses ordinary replacement.
-
Publish a same-account generation between admission and dispatch → the old admission refuses; a new admission validates/pins the new generation. A raw source change never substitutes new bytes into an existing pin.
-
Refresh narrows grants → new scope evidence refuses a write requiring the removed grant; old
scope_check: okis not copied. Permission and verification results are invalidated even when identity lineage is retained. -
Revoke or expire a credential after admission → the pin refuses dispatch;
Admittedis not enduring authority. -
Public describe is searched for secret bytes, private generation IDs, snapshot handles and secret-version references → no match.
Verification evidence and ESS limits distinguish compiled authored expectations from required runtime tests.
7. Compatibility
- Service compatibility is authoritative for the binding. The evidence block belongs to the selected managed connection payload schema, whose reader must support it. Managed metadata and new error codes require the extended codec; optionality does not make a field acceptable to an existing strict payload reader.
8. SDK and host obligations
| Obligation | Where |
|---|---|
| Evidence collector in the host with per-check effect class enforcement | new host module |
Provider hooks for identity_check, permission_check, verify_operation (optional trait methods) | crates/connectors-sdk (Adapter trait, lib.rs:18-31) |
| Generation-bound evidence values, per-check provenance/deadlines and replacement invalidation | host connection metadata, separate from opaque custody |
| Immutable material pin plus dispatch/publication/revocation ordering | host admission and capability boundary; shared coordinator controls publication |
| Explicit validation admission and identity/grant interpretation | host policy and provider auth profile; ordinary business requests cannot invent probes |
More columns: swipe horizontally, or focus the table and use the arrow keys.
9. ESS entities
Shared permission observations in auth_access.yaml refer to a private binding and exact adapter-owned target. The typed adapter tuple is in the adapter permission model. Mapping/equality and current admission remain explicit binding obligations; the selected public authorization target tuple is unchanged by this private model split.
| Entity / value | Notes |
|---|---|
EvidenceSnapshot (value on Connection) | modeled in credential_evidence.yaml: generation/binding, observed identity and per-check source/deadlines; not a separately persisted entity |
DispatchAdmission | transient per-invocation decision, Inspected → Admitted → Dispatched or Inspected/Admitted → Refused; references exactly one immutable generation; no durable-store ownership implied |
CredentialGeneration | shared model; capture alone does not validate the expected identity |
AuthProfile.evidence | which checks a profile supports (profile document) |
| SaaS policy inputs | UNMAPPED |
| Permission target/budget/coverage values | auth_access.yaml; exact binding equality, numeric ceilings, budget consumption, reduction, current authority/time and coverage completeness predicates are normative and not executed by generic ESS schemas. |
More columns: swipe horizontally, or focus the table and use the arrow keys.
10. Open decisions
| Decision | Default taken |
|---|---|
Whether credential_valid may call provider introspection by default | no; metadata only |
| Freshness bounds | 300 s reads, 60 s mutations |
| Completion-time verification | only the explicitly selected/admitted validation plan runs it. Mandatory baseline failure prevents publication/completed; optional failure preserves baseline publication but blocks any operation requiring that check. Supported is not mandatory; see profile §4.1. |
More columns: swipe horizontally, or focus the table and use the arrow keys.
Persistence ownership is consolidated in design §31. MaterialAdmissionPort owns capture/admission facts and PermissionEvidenceCachePort owns optional bounded cached checks; neither turns a value into independent current authority. This inventory does not supply a backend or execute its atomicity predicates.