Skip to content

connectors: request-signing auth kind for the openapi and rest providers (RSA2 / HMAC canonical-request signers: Alipay, WeChat Pay, Aliyun, Tencent Cloud, e签宝) — the vendor-auth half that #26702 does not cover #26710

Open

Description

@objectstack-fleet

Unblocked (triage, 2026-10-30): ADR-0143 is Accepted on main (PR #27231); #26768's only open item is the cloud mirror record (objectstack-ai/cloud#3350), which gates no code in this repo.
Filing gate ③ (maintainer-directed task). The maintainer in this session, 2026-10-27, on the three action recommendations of the MCP / OpenAPI directory survey, verbatim: 「三条行动建议 立卡」 → 「建议 1+2立卡」 → 「3 不考虑」 → 「你应该使用 pm-dispatch 技能立卡」. This card is recommendation 2, narrowed: the survey's recommendation was one ADR admitting both OAuth2 and request signing into the declarative connector auth contract. While this card was being drafted, #26702 (filed 2026-10-27 13:23Z from the maintainer's ruling 「OAuth 放开源层,先起草 ADR 修订」) took the OAuth2 half — authorization-code, client-credentials and the vendor app-credential exchange (Feishu / DingTalk / WeCom) — and owes the successor ADR. What remains uncovered is request signing, which no grant type produces: the caller signs each request with a private key or HMAC secret. This card is that half.

Filed by session_01J8VVAjRKqdoEYQ4hXxtBuf. ⛔ Not a claim. Lane suggestion: domain:spec for the auth variant (a Seam: with domain:server for packages/connectors/connector-openapi, connector-rest and packages/services/service-automation). Triage sets labels and priority. Sequencing note for triage: the successor ADR #26702 item 1 owes should decide signing in the same record (裁决一次裁清), so this card is a candidate sub-issue of #26702; it is not Blocked-by: #26702 as a whole, because the signer needs none of the grant machinery.

Business reason. The Chinese payment, cloud and e-signature platforms the marketplace's China lane needs do not use OAuth or static keys on their APIs; they sign every request:

Platform Scheme (official docs) Machine-readable spec
Alipay OpenAPI v3 RSA2 (SHA256withRSA) over a canonical request yes, OpenAPI 3.0.3 YAML (alipay/alipay-sdk-java-all v3/api/openapi.yaml, about 746 operations, 2026-09-23; repository carries no LICENSE)
WeChat Pay APIv3 WECHATPAY2-SHA256-RSA2048 none found
Aliyun OpenAPI ACS3-HMAC-SHA256 proprietary metadata (aliyun/aliyun-openapi-meta)
Tencent Cloud TC3-HMAC-SHA256 online explorer only
e签宝 (esign.cn) request signature or OAuth2 none found
AWS (for the global shelf) SigV4 Smithy models, not OAS

Without a signing auth kind, none of these is reachable from a declarative instance, whatever OAuth2 support lands; a flow that needs to create an Alipay trade or a Tencent Cloud resource cannot be authored as metadata. With it, the Alipay v3 document (the only official OpenAPI document found among Chinese platforms) becomes a drop-in openapi instance.

Who acts. The ADR author named by #26702 (the domain:skills seat drafts, the maintainer lands, Tier H) extends the record with the signing decision; then domain:spec adds the variant to ConnectorInstanceAuthSchema; then domain:server implements the signer seam in the shared transport and wires openapi and rest. Reader: app authors declaring auth: { type: 'signed', scheme: 'alipay-rsa2', … } in content/docs/automation/connectors.

Dedupe (semantic issue search, objectstack-ai/objectstack, open and closed, 2026-10-27): "connector auth OAuth2 client credentials authorization code request signing HMAC RSA access_token exchange ADR ConnectorInstanceAuthSchema" → 3 hits: #26702 (open; OAuth2 and app-credential exchange, no signing), #14506 (closed; identity ADR mirror), #8075 (closed; inline-credential census). No card covers request signing.

Governing text

Protocol statement. Metadata-protocol: added: a new ConnectorInstanceAuthSchema variant. Proposed shape, for the ADR to settle: { type: 'signed', scheme: <closed enum: 'alipay-rsa2' | 'wechatpay-rsa2048' | 'aliyun-acs3-hmac-sha256' | 'tencentcloud-tc3-hmac-sha256' | 'aws-sigv4' | 'hmac-sha256-generic'>, keyId: string, credentialRef: string, …scheme-specific non-secret parameters }. The private key or HMAC secret is a credentialRef only (ADR-0097 §3). Skills-docs: follow-up owed — content/docs/automation/connectors, skills/objectstack-automation.

Premises (each with a re-check; read at c3fb185a)

  1. No signing kind exists in either the declarative or the runtime auth union. Re-check: git grep -n "z.literal('" origin/main -- packages/spec/src/shared/connector-auth.zod.ts (expected: oauth2, api-key, basic, bearer, none only).
  2. The openapi provider applies one static auth globally and ignores securitySchemes. Re-check: git grep -n "securitySchemes" origin/main -- packages/connectors/connector-openapi/src/openapi-connector.ts (type only, no consumer).
  3. connectors: outbound OAuth in the open tier — connection-scoped authorization-code / client-credentials / app-credential tokens, refreshed per dispatch, for the openapi, mcp and rest providers #26702 does not list signing in its grant types or its spec variant. Re-check: read connectors: outbound OAuth in the open tier — connection-scoped authorization-code / client-credentials / app-credential tokens, refreshed per dispatch, for the openapi, mcp and rest providers #26702 "Work" items 3 and 5.

Work

  1. ADR (with connectors: outbound OAuth in the open tier — connection-scoped authorization-code / client-credentials / app-credential tokens, refreshed per dispatch, for the openapi, mcp and rest providers #26702 item 1): admit a signed auth kind with a closed scheme enum into the open tier; state which schemes ship first and that the secret is always a credentialRef.
  2. Spec: the variant above in ConnectorInstanceAuthSchema, publish-time refusal of an unknown scheme and of any inline key.
  3. Runtime: a RequestSigner seam in the shared connector transport (packages/services/service-automation or the connectors' shared layer, triage's call): given the resolved secret and the outgoing request (method, URL, headers, body), produce the signed headers / query. First signers: alipay-rsa2, aliyun-acs3-hmac-sha256, tencentcloud-tc3-hmac-sha256; aws-sigv4 and wechatpay-rsa2048 follow when a consumer declares them. Signers are pure functions with vectors from the vendors' published examples.
  4. Providers: openapi and rest accept the variant; mcp does not (MCP servers do not sign; out of scope).

Acceptance

Out of scope

Related

#26702 (parent candidate) · ADR-0097 · ADR-0015 · ADR-0023 · #26709 (recommendation 1, same batch).


Generated by Claude Code

Activity

  1. objectstack-fleet commented on Oct 27, 2026

    @objectstack-fleet
    ContributorAuthor

    Triage: first grade — enhancement · security · priority:p1 · domain:server · area:api · pm:queue · triage seat · session_01AavokzJ5DndAwitDXvKy4U · 2026-10-27T14:17Z

    ⛔ Not a claim, ⛔ not a dispatch.


    Generated by Claude Code

  2. added
    area:apiThe API a customer can call, and integrations — REST, connectors, webhooks, jobs
    domain:serverDomain lane — seat card indexed by label:pm:seat
    priority:p1High: required for production / M2
    and removed on Oct 27, 2026
  3. objectstack-fleet commented on Oct 27, 2026

    @objectstack-fleet
    ContributorAuthor

    pm:queue → pm:blocked · domain:server seat 3 · session_01QSeKYmQXM3rHJcPnrEPk4B · 2026-10-27T15:10Z

    Blocked-by: #26768

  4. objectstack-fleet commented on Oct 28, 2026

    @objectstack-fleet
    ContributorAuthor

    Part of #27293 (E1 platform prerequisites) · 2026-10-28T14:59Z

    Epic link on the maintainer's ruling 「是否建议立专题卡统一处理。」→「同意」 (2026-10-28, session_01J8VVAjRKqdoEYQ4hXxtBuf). Role in the chain: the request-signing auth kind that admits the signature-authenticated half of E4 (Alipay v3 first); decided in the same ADR as #26702. Lane claims and dispatch proceed as triage set them; the epic PM seat (epic:#27293) tracks this card and reserves only what it drives in order. ⛔ Not a claim.


    Generated by Claude Code

  5. objectstack-fleet commented on Oct 28, 2026

    @objectstack-fleet
    ContributorAuthor

    epic:#27293#1 · sunhaolin · session_017xRBcVBKAFk1ntXSjvPt7U

    Reserved for the epic subtree · 2026-10-28T15:12Z — pm:epic added; pm:blocked (Blocked-by: #26768) unchanged.

    The maintainer in session_017xRBcVBKAFk1ntXSjvPt7U, 2026-10-28, verbatim: 「有很多子卡,这是没有挂到子任务,你应该处理。」 This card is attached under #27293 and now carries pm:epic: other seats' candidate reads skip it; the epic PM claims it with the full claim protocol when it dispatches. ⛔ Not a claim, ⛔ not a dispatch.

  6. objectstack-fleet commented on Oct 29, 2026

    @objectstack-fleet
    ContributorAuthor

    triage#1 · os-zhuang · session_01AavokzJ5DndAwitDXvKy4U

    Path: 可对外的 API | none | P②

    Triage: unblocked · p1 kept · domain:server · 2026-10-29T04:02Z

    ⛔ Not a claim.


    Generated by Claude Code

  7. 4 remaining items

  8. objectstack-fleet commented on Oct 30, 2026

    @objectstack-fleet
    ContributorAuthor

    triage#1 · os-zhuang · session_01AavokzJ5DndAwitDXvKy4U

    Path: none

    Triage: label hygiene · pm:epic reservation released · 2026-10-30T04:59Z

    ⛔ Not a claim.


    Generated by Claude Code

  9. added and removed
    pm:retriageQuestion for triage, answered each fire; coexists with the standing pm:* label; no dispatch
    on Oct 30, 2026
  10. objectstack-fleet commented on Oct 30, 2026

    @objectstack-fleet
    ContributorAuthor

    triage#1 · os-zhuang · session_01AavokzJ5DndAwitDXvKy4U

    Path: 可对外的 API | none | P②

    Triage: unblocked · p1 · domain:server · pm:queue · 2026-10-30T12:28Z

    ⛔ Not a claim. Correction, and triage's miss: in R761 triage set pm:blocked on the body line Blocked-by: #26768 without reading what #26768 still owed.


    Generated by Claude Code

  11. objectstack-fleet commented on Oct 30, 2026

    @objectstack-fleet
    ContributorAuthor

    domain:server#3 · os-elon-musk · session_016WV4czuTWNgKR22fKv7jia

    Claim: PM loop round 2 · 2026-10-30T22:50Z
    Session: session_016WV4cxRP1AqTeP2PWAhwGK (card thread; seat session_016WV4czuTWNgKR22fKv7jia)
    Account: os-elon-musk
    Branch: claude/project-thread-tpb1yk (the card thread's platform-assigned branch — the recorded platform exception; amended by the seat when the thread reported it)
    Worktree: objectstack-issue-26710
    Domain: domain:server
    Seat: domain:server#3
    File surface: amended from the thread's slice plan (S1, /mnt plan read by the seat). Spec seam (domain:spec paths carried as Seam): packages/spec/src/shared/connector-auth.zod.ts (the signed variant), packages/spec/src/integration/connector-provider.ts (ConnectorRequestSigner, ConnectorProviderContext.requestSigner, the materialization acknowledgement), packages/spec/src/integration/connector.zod.ts (re-exports; signed on provider: mcp refused), packages/spec/src/integration/connector-fetch-policy.ts (per-attempt signing wrap, shared response reader); their tests and type-alias-convention.pin.test.ts; generated artefacts by repo tooling only (packages/spec/{api-surface,authorable-surface,declaration-map,export-origins,json-schema.manifest}/integration.json, packages/spec/variant-docs.json, content/docs/references/**, the unknown-key strictness ledger counts, packages/spec/liveness/connector.json if asked); packages/spec/docs/SYNC_ARCHITECTURE.md. Server: packages/services/service-automation/src/request-signing/** (new; exhaustive scheme switch), service-automation/src/plugin.ts (reconcile builds the signer, fails closed without the acknowledgement), connector-credential-source.ts (lendRefusal) and connector-materialization.test.ts; packages/connectors/connector-openapi/src/{openapi-connector,openapi-provider}.ts and packages/connectors/connector-rest/src/{rest-connector,rest-provider}.ts with tests; packages/qa/downstream-contract/src/additional-domains.fixtures.ts if the fixture walk asks; scripts/adr-anchors/*.json (new ADR-0143 anchors); content/docs/automation/connectors.mdx; .changeset/*. Not touched: resilient-fetch.ts, connector-mcp, inbound auth, OAuth2 grant machinery (#26702), skills/**. Later slices (S2 tencentcloud-tc3-hmac-sha256, S3 alipay-v3 + response verification) add their signer files under the same folders.
    Container & model: L, mode:thread, model: opus (TIER_DEFAULT), effort: xhigh (p1, security)
    Clause-②: yes (a new auth variant on a published schema)
    Metadata-protocol: added (a new ConnectorInstanceAuthSchema variant)
    Responsibility: an app author declaring auth: { type: 'signed', scheme, keyId, … } on an openapi / rest connector instance, with the secret only as a credentialRef, and every outbound request signed by a shipped signer whose output reproduces the vendor's vectors; an enum member without a shipped signer is not admitted (ADR-0049).
    Thread-read: 6522856999
    Ruling-ref: ADR-0143 (Accepted on main, PR #27231), Q4 letter A with its condition 1 naming the Alipay member alipay-v3 (not alipay-rsa2): alipay-v3, aliyun-acs3-hmac-sha256, tencentcloud-tc3-hmac-sha256
    Premise: read on main @ f64724ac: ConnectorInstanceAuthSchema declares none | bearer | api-key | basic only; the thread re-reads and plans slices before code.
    Serial constraints cleared: no open PR touches connector-auth.zod.ts, connector-openapi or connector-rest (checked against the open PR list).
    Dispatch-note: p1, security: rule-level text only on GitHub. CONTRACT_REVIEW_TIER review owed (spec path, Clause-② yes) before any approval. Expected to land as slices; each slice PR names its part. Claimed with the coordinator's go under the project-wide cap of 10 (2026-10-30 22:48Z).

  12. objectstack-fleet commented on Oct 31, 2026

    @objectstack-fleet
    ContributorAuthor

    domain:server#3 · os-elon-musk · session_016WV4cxRP1AqTeP2PWAhwGK
    os-dev-report

    {
      "issue": 26710,
      "status": "done",
      "branch": "claude/project-thread-tpb1yk",
      "pr": "https://github.com/objectstack-ai/objectstack/pull/28273",
      "session": "session_016WV4cxRP1AqTeP2PWAhwGK",
      "premise_still_valid": true,
      "summary": "Slice 1 of 3 of the seat-accepted plan; the PR carries Refs #26710, so the card stays open for S2 (tencentcloud-tc3-hmac-sha256) and S3 (alipay-v3 with response verification, Fixes). S1 adds the signed kind of declarative connector-instance auth with one scheme, aliyun-acs3-hmac-sha256: scheme + public keyId + the signing key as credentialRef only. Publish refuses an unknown or missing scheme by name, inline key spellings, an authored signature, and signed on provider mcp. The host binds the resolved key to the scheme signer and hands providers only the signer (with an optional response-verification step); rest and openapi sign every attempt including retries and acknowledge it; a provider that does not acknowledge is refused at boot; a datasource borrow of a signed instance is refused 422. bearer/api-key/basic are unchanged.",
      "tests": "Vendor vector: Alibaba Cloud V3 signature worked example reproduced byte for byte (canonical request, string to sign, signature, Authorization); wrong key differs. vitest: spec integration + pins 13 files 211 passed; service-automation request-signing + materialization + credential-source 93 passed; connector-rest 32 passed; connector-openapi 75 passed. typecheck green for spec, service-automation, connector-rest, connector-openapi. Ablations (on-disk mutation, restored via git checkout): host acknowledgement check removed -> 2 boot-refusal pins red; signature cached across attempts -> per-attempt pin red; rest provider not passing the signer -> 4 pins red incl. end-to-end.",
      "gates": "dispatch-gates --commands derived 115; all run with exit codes recorded before any pipe; 3 first exited 3 (prerequisites: pinned teardown fixture fetch, dist closure) and exited 0 on rerun; --ran: 115 run, 0 NOT-MEASURED, 0 UNRUN. pnpm lint exit 0. check:generated --fix regenerated api-surface, export-origins, declaration-map, docs, strictness-ledger and re-checked green; check:variant-docs green. CI check-runs on the PR: pending at report time.",
      "dogfood_battery": "n/a — no ! in the PR title and no (narrowing) arm",
      "mcp_calls": "reads only (issue_read, search_pull_requests, pull_request_read); no write tool",
      "api_writes": "2 via fleet-write relay: pr_create (#28273, with assignees as the seat lane PRs carry), this comment. git push is not a REST write.",
      "open_questions": [],
      "out_of_scope_findings": [
        "carrier: #28226 · skills/objectstack-automation text for the signed kind rides the existing skills follow-up (a skills/** edit would make this slice Tier H)"
      ]
    }
  13. objectstack-fleet commented on Oct 31, 2026

    @objectstack-fleet
    ContributorAuthor

    domain:server#3 · os-elon-musk · session_016WV4czuTWNgKR22fKv7jia

    ACCEPT → PR #28273 (slice 1 of 3: the signed kind and aliyun-acs3-hmac-sha256) · 2026-10-31T00:53Z · contract review PASS 6536676170 (CONTRACT_REVIEW_TIER, head 8c6135c7) · ready + auto-merge armed through the relay. The card stays open for S2 and S3.

  14. objectstack-fleet commented on Oct 31, 2026

    @objectstack-fleet
    ContributorAuthor

    domain:server#3 · os-elon-musk · session_016WV4cxRP1AqTeP2PWAhwGK
    os-dev-report

    {
      "issue": 26710,
      "status": "done",
      "branch": "claude/project-thread-tpb1yk",
      "pr": "https://github.com/objectstack-ai/objectstack/pull/28279",
      "session": "session_016WV4cxRP1AqTeP2PWAhwGK",
      "premise_still_valid": true,
      "summary": "Slice 2 of 3 of the seat-accepted plan, on a branch restarted from main after #28273 merged; the PR carries Refs #26710, so the card stays open for S3 (alipay-v3 with response verification, Fixes). S2 adds tencentcloud-tc3-hmac-sha256 to the closed signing-scheme list with its signer and its own strictObject shape: scheme + public keyId (the SecretId) + the SecretKey as credentialRef only. The publish refusals of S1 apply to the new shape (inline key spellings by name, an authored signature, signed on provider mcp); secretId is answered with keyId; the unknown-scheme refusal names both shipped schemes. Every attempt is signed with a fresh X-TC-Timestamp over content-type and host. Folds in the #28273 review nit: ConnectorRequestSigner.scheme is typed by the scheme list (unreleased interface). bearer/api-key/basic and the aliyun scheme are unchanged.",
      "tests": "Vectors: the two sign3 cases (POST application/json, GET form) of the official tencentcloud-sdk-nodejs release 4.1.336 test/common/sign.test.ts reproduced byte for byte with that suite's placeholder key pair; the test file names the SDK, release and file; wrong key differs. vitest: spec signed + fetch-policy + grant-kinds + connector-auth + pins 74 passed; service-automation signing + materialization + credential-source 105 passed; connector-rest 33 passed (new tencent end-to-end); connector-openapi 75 passed. typecheck green for spec, service-automation, connector-rest. Ablations (on-disk mutation, restored via git checkout): registry case removed -> service-automation typecheck TS2322 naming the unhandled shape; TC3 key prefix dropped -> 6 vector pins red.",
      "gates": "dispatch-gates --commands derived 105; all run with exit codes recorded before any pipe, all exit 0; --ran: 105 run, 0 NOT-MEASURED, 0 UNRUN. pnpm lint exit 0. check:generated --fix regenerated api-surface, export-origins, declaration-map, authorable-surface, json-schema manifest, docs references and strictness ledger, re-checked green; check:variant-docs green. CI check-runs on the PR: pending at report time.",
      "dogfood_battery": "n/a — no ! in the PR title and no (narrowing) arm",
      "mcp_calls": "reads only (issue_read, pull_request_read, search_pull_requests); no write tool",
      "api_writes": "2 via fleet-write relay: pr_create (#28279, with assignees as the seat lane PRs carry), this comment. git push is not a REST write.",
      "open_questions": [],
      "out_of_scope_findings": [
        "carrier: #28226 · skills/objectstack-automation text for the signed kind rides the existing skills follow-up (a skills/** edit would make this slice Tier H)"
      ]
    }
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Labels

area:apiThe API a customer can call, and integrations — REST, connectors, webhooks, jobsdomain:serverDomain lane — seat card indexed by label:pm:seatenhancementNew feature or requestpm:dispatchedpriority:p1High: required for production / M2security

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions