75 lines
5.5 KiB
Markdown
75 lines
5.5 KiB
Markdown
# Security, validation, and expiration contract
|
|
|
|
- Document status: active reference implementation
|
|
- Last code-and-document review: 2026-07-12
|
|
- Review by: 2026-10-12, or sooner when the MCP SDK/protocol baseline changes
|
|
Stable protocol evidence baseline: MCP 2025-11-25; provider support must still
|
|
be verified against the deployed ServiceNow or Microsoft surface.
|
|
|
|
This document is intentionally time-bounded. A reviewer must re-check the live
|
|
SDK, MCP specification, provider documentation, and Den adapter before changing
|
|
the review date. A date alone is not evidence of provider conformance.
|
|
|
|
## Required composition contracts
|
|
|
|
| Boundary | Package requirement | Den responsibility |
|
|
| --- | --- | --- |
|
|
| Network | A fetch port is required; all requests share cancellation/deadline signals. | Enforce protocol, credentials, DNS/IP policy, redirects, downgrade rules, cross-origin secret stripping, proxy/TLS posture, response limits, and body cancellation. |
|
|
| Clock | Absolute epoch-millisecond values; finite/non-negative validation. | Supply deployment time; monitor clock skew operationally. |
|
|
| Tenant and actor | No tenant/member model in the package. | Construct an adapter already scoped to exactly one organization, connection, and shared/member credential owner. |
|
|
| Client registration | Opaque revision, source, and expiry. Concurrent DCR is first-writer-wins. | Encrypt the secret, omit secrets from JSON metadata, serialize competing writers, and reject a losing client. |
|
|
| Authorization | Signed id, verifier, expiry, optional client revision, opaque transaction revision. | Store only a non-reversible state key plus encrypted verifier; cap transactions and enforce single-use. |
|
|
| Credentials | Validated OAuth token wire value plus absolute expiry and opaque revision. | Encrypt tokens and atomically persist/consume under connection and identity locks. |
|
|
| Diagnostics | Secret-free phase events; observer failures cannot affect behavior. | Add safe classification, correlation reference, authorized support evidence, retention, and audit. |
|
|
|
|
## Expiration rules
|
|
|
|
| Record | Validation | Expired behavior |
|
|
| --- | --- | --- |
|
|
| Operation lifecycle | `now < commitExpiresAt` before and immediately before transaction commit; abort signal remains active. | Reject/roll back with `MCP_LIFECYCLE_DEADLINE`; never commit after a reported timeout. |
|
|
| OAuth authorization/PKCE | Absolute expiry, signed state id, transaction revision, client revision; Den state verification is an additional outer check. | Delete the transaction and require Connect to restart. It cannot be reused. |
|
|
| Access token | Persist absolute expiry computed from `expires_in`; reject invalid/negative lifetimes. | With a refresh token, allow the bounded SDK refresh path. Without one, invalidate and require reconnect. |
|
|
| Refresh token | Opaque; provider rotation is authoritative. | Preserve the previous refresh token only when a successful refresh response validly omits a replacement. Invalid grant is reconnect-required, not generic retry. |
|
|
| OAuth client/client secret | Absolute `client_secret_expires_at` when declared; `0` means no declared expiry per DCR convention. | Invalidate and require client renewal/re-registration. Do not silently use an expired secret. |
|
|
| Documentation/provider assumptions | `Last review` and `Review by` above. | Revalidate against primary sources and a nonproduction tenant; never promote a stale preview/patch assumption. |
|
|
|
|
The default clock-skew allowance is 30 seconds and is configurable only at
|
|
client construction. It is not an environment read inside the package.
|
|
|
|
## Validation and failure ownership
|
|
|
|
Validation happens before secrets cross a boundary whenever possible:
|
|
|
|
- configuration: non-empty ids, HTTP(S) URLs, no URL credentials/fragments,
|
|
bounded OAuth state/code, positive timeouts and TTLs;
|
|
- persistence: OAuth wire schemas, opaque revisions, finite expirations,
|
|
matching authorization/client revisions, correct credential identity;
|
|
- protocol: initialize first, bounded complete pagination, tool schemas,
|
|
provider `isError`, close within deadline;
|
|
- adapter: tenant/member scope, encrypted columns, same-row transaction locks,
|
|
safe public origin, and guarded outbound requests.
|
|
|
|
Stable package codes distinguish missing/expired authorization, changed/expired
|
|
client registration, expired credentials, invalid persistence, and lifecycle
|
|
deadline. Den maps those codes to a safe phase, owner, remediation, and
|
|
diagnostic reference. Raw provider messages are not the administrator contract.
|
|
|
|
## Known evidence boundary
|
|
|
|
The deterministic OAuth/MCP tests prove protocol and port semantics. They do
|
|
not prove a real customer's ServiceNow ACL/domain policy, Microsoft consent or
|
|
Conditional Access, provider licensing/preview availability, egress allowlist,
|
|
or mutation behavior. Those remain explicit nonproduction conformance gates.
|
|
|
|
Pre-existing records written by another implementation may contain historical
|
|
provider metadata in the generic JSON column. This package never writes OAuth
|
|
client secrets or registration access tokens there. A separate reviewed data
|
|
cleanup is required before claiming that historical rows were rewritten; this
|
|
PR does not silently mutate every existing record at startup.
|
|
|
|
Pending PKCE data is intentionally not cross-mode compatible: current mode has
|
|
one unbound verifier, while enterprise mode has a versioned collection of
|
|
state-bound transactions. Feature-flag rollout/rollback must drain or expire
|
|
in-flight browser authorizations first. The adapter fails closed instead of
|
|
guessing a transaction identity for an old verifier.
|