auth.capability/v1alpha1
Rendered from contracts/auth/capability/v1alpha1/semantics.md by connectors-docs; the source owns every rule on this page.
- Status: proposed, not implemented. Extends the existing
AuthenticatedHttpport (crates/connectors-sdk/src/lib.rs:53-56, GET only). - Family: auth. Sibling documents: connection, profile, acquisition, custody, evidence.
- Recorded: 2026-09-08.
1. Identity
| Field | Value |
|---|---|
| Contract | auth.capability/v1alpha1 |
| Capabilities | http-bearer, http-basic, http-signing, http-anonymous, mtls-client-identity, socket-peer, exec-credential-plugin, sip-credential-lease, session-authority, inbound-verifier, mediated-http |
| Nature | the runtime side of authentication: a connection-bound object handed to provider code that authenticates one permitted request at the trusted execution boundary |
More columns: swipe horizontally, or focus the table and use the arrow keys.
Design responsibility four of four (docs/design.md:529): "Authenticate a permitted provider request — connection-bound authentication capability at the execution boundary." The requirement is a defined trusted boundary, no general secret-store access from business operations, and no leakage through public interfaces (docs/design.md:592).
3. Types
Each capability is a Rust port in the SDK; none is a wire type. The wire only ever sees the capability name in descriptors and profiles.
HttpCapability
request(method, segments, query, headers_allowlisted, body_bounded) -> HttpResponse
// bound to: connection, profile, admitted credential/configuration/route binding, destination aperture, deadline, body limits
// variants: http-bearer, http-basic, http-signing, http-anonymous, mediated-http
TransportIdentity
tls_client_config() -> ClientIdentity // mtls-client-identity: certificate chain + key handle
socket_path() -> PathBuf // socket-peer: owner-checked unix socket
ExecCredentialPlugin
materialize(deadline) -> ShortLivedCredential // exec-credential-plugin: runs the configured helper under the plugin policy
CredentialLease
acquire(purpose, deadline) -> LeasedMaterial // sip-credential-lease: bytes released to the protocol library for one establishment
release(lease)
SessionAuthority
issue(binding) -> Authority // session-authority: one-time, proof-bound, short-lived
InboundVerifier
verify(presented, proof, original_bytes) -> Verified(binding) | Refused
redeem(authority_id) -> Redeemed | AlreadyRedeemed
Every capability carries the binding it was created for. Credential-bearing bindings additionally contain the validated generation pin and its admission. Anonymous direct and mediated child capabilities use the explicit no-child-credential binding in profile §4.2; the parent's own capability retains its generation pin. Private bindings do not appear in this safe descriptive example:
{ "connection": "conn_…", "profile": "jira.user_oauth", "destination": { "origin": "https://api.atlassian.com", "base_path": "/ex/jira/<cloud_id>" }, "limits": { "deadline_ms": 15000, "body_bytes": 4194304 } }
4. Rules
- Binding: a capability is constructed by the host for one connection and one profile, with the admitted destination and limits. Provider code cannot change the credential, the destination origin, or the limits through the request it builds (
docs/design.md:590). - Placement for credential-bearing capabilities: the host captures immutable material, validates it through the declared admitted auth flow, and pins that exact generation with the evidence used for admission. Immediately before dispatch the capability places the pinned material; it must not resolve a mutable path afresh or silently substitute a newer custody reference. Provider code never sees
http-bearer/http-basicbytes. The pin is host-private and no public serializer or diagnostic exposes its generation or snapshot reference. http-bearerplaces one token in one header: bare, afterBearer, or after one declared scheme word (<word> <token>, such as Opsgenie'sAuthorization: GenieKey <key>). The word is part of the admitted configuration, never of the request provider code builds; the catalog provider declares it as a token profile'sauth.prefix, refused besidebearer: true.http-anonymousis bound only to the explicit anonymous profile and admitted destination/configuration revision. It performs no credential resolution, placement, cookie/ambient authentication or refresh. Provider/user input cannot add Authorization or select another access profile. A 401 is a provider refusal, never a trigger to acquire credentials or retry under another mode.mediated-httpsimilarly owns no child credential: it passes only reviewed target-relative traffic to the independently admitted parent's fixed route, never the parent's secret or arbitrary destination.- Dispatch consistency for credential-bearing capabilities: final dispatch must establish that the pin, evidence and selected connection binding agree and the generation remains current and usable. Known revocation/expiry, stale required checks, a detected unvalidated replacement, or an unresolved authorized rotating refresh refuses even a pin. Successful refresh/replacement publication atomically cuts off old pending admissions; a new admission is required for the new generation. A capability cannot renew authority just by reloading credentials. See evidence §4.
- Non-material dispatch still requires a current host admission and immutable configuration/route aperture ordered against revocation and binding changes.
socket-peervalidates and pins the admitted local path/peer/transport identity for use; it does not turn socket metadata into CredentialGeneration or anonymous HTTP. Its concrete peer/path race checks and typed transport admission remain UNMAPPED advertisement gates. Anonymous and mediated binding predicates likewise cannot be represented as a fake material-bearing DispatchAdmission. - Destination:
http-*capabilities refuse a request whose resolved URL leaves the admitted origin and base path; redirects are not followed (docs/design.md:590; current host behavior). - Business methods:
GET,POST,PUT,PATCH,DELETEwith a bounded body; a mutation method is refused when the operation's profile is notmutation(operationsdocument). Separately admitted auth checks use private purpose-specific capabilities: for example the bounded SSAR POST in evidence §4.4 grants no business POST authority. - Read sent as a POST (
post_json): some providers serve a read only as a POST with a JSON body, as the websearch family does. Trusted composition fixes, once, the exact paths an adapter may POST to as reads and their deadline (ScopedHttp::with_read_posts), from the operations the adapter's descriptor declares reads sent as a POST. Any other path is refused before dispatch, as is a body over the request limit. The port carries no write approval, records no attempt and grants no mutation authority; an adapter that declares a POST read takes responsibility that the provider changes nothing a caller can observe. Its response is bounded as a GET's is, and redirects are not followed. - Provider 401 and refresh: a capability name grants neither an exchange nor redispatch. Only the explicitly selected supported read-refresh-once/v1alpha1 binding permits its one complete business-response 401 to trigger one coordinated refresh participation and at most one new-generation redispatch. It retains the original deadline, exact request/authority and consumed permission-call ledger; failed authorization checks do not become refresh triggers. Legacy and unselected reads retain their own terminal no-retry behavior. Separately admitted auth maintenance remains governed by acquisition, with its own effects and no implicit repeat of the business operation. Mutations never redispatch after refresh. Anonymous/static_config modes never acquire/refresh implicitly, and mediated/federated traffic cannot select this first retry binding; parent maintenance never grants a child a silent repeat.
- Leases (
sip-credential-lease,exec-credential-plugin): material is released for one establishment or one helper run, within a deadline, and is not retained by provider code beyond the protocol object that consumes it. The lease records purpose and time, never the value. exec-credential-pluginruns only when configuration enables it and only inside an admitted operation or explicitly admitted activation/revalidation step, never during listing or description (old rule preserved). One helper output is one captured generation: identity validation and dispatch must consume the same output. Running the helper a second time needs a new generation and admission. Client-certificate capabilities similarly pin one coherent certificate/key pair through transport use. An identity probe needed for replacement belongs to the declared validation step; it is not an implicit expansion of a business operation.session-authority: issued per admitted session with a bound lifetime (old profile: 60 s, single redemption); the verifier redeems atomically before any media or data byte is accepted; a second presentation isAlreadyRedeemed.- Establishment redemption is necessary but does not authorize an established session indefinitely. Every data path additionally enforces the authenticated live data lease and cutoff policy in sessions §4.1. The 60 s token lifetime does not extend the at-most-2 s live lease, grant grace after revocation/expiry, or revive a terminal session.
inbound-verifierverifies over the original received bytes, not a re-serialized copy (docs/design.md:726).- No public serializer or
Debugon any type that can hold material (Secretpattern,crates/connectors-sdk/src/lib.rs:33-34).
5. Limits
| Concern | Rule |
|---|---|
| Deadlines | inherited from the operation profile (today 15 s provider, 5 s connect); a read sent as a POST takes the deadline its composition fixes, at most 180 s |
| Body | inherited (64 KiB request, 4 MiB response today); mutation bodies bounded by the operation's declared limit |
| Lease lifetime | one establishment; default ceiling 30 s for SIP, plugin deadline 10 s (first-profile defaults) |
| Authority lifetime | 60 s from the old profile as the starting value |
More columns: swipe horizontally, or focus the table and use the arrow keys.
6. Conformance scenarios
- Fake transport records the header for
http-bearerandhttp-basic; provider code has no access to the value (type-level: the capability owns it). - Request built with an absolute URL or a
..segment → refused before dispatch. - Redirect from the fake provider → not followed;
UpstreamProtocol. - Legacy or unchanged read profile 401 → one business call and its documented error, with no refresh/redispatch caused by this invocation. Explicitly selected read-refresh-once/v1alpha1 → follow its complete bounded sequence and refusal matrix; second 401 is terminal, and new-generation permission checks cannot reuse consumed per-invocation slots. Mutation redispatch remains zero. Anonymous/static_config read 401 never upgrades auth; mediated child never refreshes the parent or silently repeats a forward.
post_jsonto a path the composition did not fix, or with a body over the request limit → refused with no request sent; a port built withoutwith_read_postsanswersunavailable.- Lease released twice → second release is a no-op; lease used after deadline → refused.
- Authority redeemed twice →
AlreadyRedeemed; media bytes before redemption → refused. - Swap the custody implementation while preserving the exact immutable snapshot semantics → authentication behavior remains compatible. Swapping material is a new generation, never permission to retain old evidence.
- Publish a replacement between admission and dispatch → the old capability refuses; a fresh admitted capability uses only the validated new generation.
- A helper returns account A material during validation and would return B on a second run → dispatch uses the captured A output or refuses; it never runs the helper again under A's evidence.
- Revoke/expire a pinned generation or authorize a rotating refresh without a definitive result → the pin refuses dispatch.
7. Compatibility
http-beareris today'sAuthenticatedHttprenamed;getremains as a convenience.- Service compatibility is authoritative for the binding. Private capability ports do not themselves change wire bytes. Publishing capability names through
Descriptor.auth_profilesrequires the extended codec; only an unchanged configured port and public surface may keep legacy behavior. - Read retry is a separate observable profile change, not part of the port rename. The proposed combined native read profile uses the existing singular Operation.profile and a changed projection revision on v1alpha2; it is excluded from legacy projection and unadvertised until actually implemented. No capability, adapter-kind or invocation field is added here.
8. SDK and host obligations
| Obligation | Where |
|---|---|
AuthenticatedHttp → HttpCapability with methods and body; basic scheme with user half | crates/connectors-sdk/src/lib.rs:53-56; crates/connectors-host/src/http.rs:11-35 |
| TLS client identity and unix-socket transport in the host HTTP client | crates/connectors-host/src/http.rs |
Read sent as a POST: AuthenticatedHttp::post_json, fixed paths and deadline from ScopedHttp::with_read_posts | crates/connectors-sdk/src/lib.rs; crates/connectors-host/src/http.rs (implemented) |
| Generation pin and dispatch/publication/revocation ordering | host admission/capability boundary with the shared auth coordinator |
| Lease, plugin, authority, verifier ports | crates/connectors-sdk (traits), crates/connectors-host (bindings) |
| Mediated-http implementation | host, per mediated_route |
More columns: swipe horizontally, or focus the table and use the arrow keys.
9. ESS entities
| Entity / value | Notes |
|---|---|
AuthProfile.capabilities | value list (profile document) |
SessionAuthority (identity: authority id), lifecycle `issued → redeemed | expired` |
| Leases | not persisted; transient adapter state (docs/design.md:959); generation pins are trusted host state |
DispatchAdmission | transient host decision modeled in credential_evidence.yaml; references one CredentialGeneration, without inventing a durable lease entity |
More columns: swipe horizontally, or focus the table and use the arrow keys.
10. Open decisions
| Decision | Default taken |
|---|---|
Whether provider code may see http-basic bytes for libraries that require them | no; the capability places the header |
| SIP lease ceiling | 30 s |
http-signing canonicalization | deferred with the providers that need it |
More columns: swipe horizontally, or focus the table and use the arrow keys.