You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
0.0.7 normative scope amendment — 2026-08-13. RFC 0001 Stage 4 supersedes conflicting rows
below. Ship the @netscript/plugin-auth-core/sdk bearer credential contribution, access-metadata
behavior, secret redaction, partitioned/direct-only cache rules, plugin manifest reference, docs,
and explicit scaffold/app selection. Cookie/session transport does not land in this issue and
the canonical module path is @netscript/plugin-auth-core/sdk. The contribution must compose
only through the Stage-2 public protocol and must not expose upstream oRPC identities.
Summary
@netscript/service/auth reads Authorization: Bearer … and x-api-key, and createServiceClient cannot send either — the SDK has no concept of a credential at any layer.
NetScript's own CLI proves the consequence: it calls the auth service with raw fetch and
hand-rolled JSON shape-sniffing rather than the typed client it already depends on. This issue makes
auth the first dogfood consumer of the RFC-A contribution chain: a first-party authClient(…) / authContribution(…) that attaches credentials, reads procedure policy metadata, surfaces a defined
credential error, and is declared from the auth plugin's manifest — so the seam is validated by the
sharpest real consumer rather than by a toy.
Source at baseline fac9e339042c (re-verified for this draft):
packages/service/src/auth/static-credential-authenticator.ts:108-117 — server reads Authorization: Bearer … and x-api-key.
packages/sdk/src/client/http-client-link.ts:82-101 — the client's entire header authorship is Content-Type plus optional traceparent/tracestate. grep -rn 'Authorization' packages/sdk/src
→ no match.
packages/sdk/src/ports/service-client.ts:129-155,203-222 — no credential field on the options
record or on per-call context.
grep -rn 'authClient' packages plugins → no such symbol exists; this issue creates it.
packages/plugin/src/config/domain/plugin-contributions.ts:12-39 — no client contribution group; :16 is the closed-literal precedent to avoid.
grep -rnE '\$meta<|\.meta\(' packages plugins → no oRPC procedure metadata anywhere, so policy.public has no current consumer to conflict with.
packages/plugin-streams-core/src/application/stream-url-resolver.ts:136-150 — getStreamsAuth()
is the repo's only working credential header, built outside the typed client; existence proof
that a header seam fits this architecture.
Server-side auth is real and correctly ordered — withAuthn/withAuthz install before RPC routes
mount, authz fails closed, and the principal reaches the oRPC handler context
(research/repo-audit/auth.md §1.1). Client-side there is nothing: no credential option, no
per-call override, no cookie forwarding, no emitter for the trusted-header authenticator that packages/service/src/auth/trusted-header-authenticator.ts:32-54 is waiting for. The docs cannot
show an authenticated typed call because none can be written — the authz tutorial can only show curl -H 'authorization: Bearer read' (docs/site/tutorials/workspace/05-route-authz.md:248-258).
Target contract
A first-party contribution shipped from the auth plugin, consumed through the RFC-A chain:
authContribution(options) declares { auth: { token: string } } as per-call context, so
oRPC's ClientRest makes it required at the call site — omitting it is a compile error, not a
401. A server-only variant (@netscript/plugin-auth/sdk/server) may close over a resolver that
reads a secret; the isomorphic descriptor never does.
authClient(...) is the convenience wrapper the CLI and generated apps use: a createServiceClient pre-composed with the auth contribution against authContractV1, replacing
the raw-fetch client at packages/cli/src/public/features/plugins/auth/auth-session-client.ts.
Policy-aware behaviour. The contribution reads NetScriptProcedureMeta.policy (RFC-A §3.6):
it does not attach a credential to a policy.public procedure, and it raises a defined CREDENTIAL_UNAVAILABLE rather than sending an unauthenticated request to a non-public one.
Declared from the manifest. The auth plugin declares the contribution through the PluginContributions client group added by RFC-A — with a nameable, non-closed shape (contrast plugin-contributions.ts:16).
Scheme scope is bounded by RFC-A Q1. Bearer and x-api-key land here. Cookie/session
transport does not — research/repo-audit/auth.md §4.2 proves it cannot work across the
current cross-origin discovery + __Host- prefix + origin:'*' CORS combination, and the
topology decision is the auth pack's.
Application code supplies the bearer token/context, and the CLI's direct auth requests migrate to
the typed SDK path without a server-only import.
Guarded-call integration proves the expected Authorization header arrives, the unauthenticated
path is rejected, and absence of the contribution sends no credential.
Authentication identity participates in response-cache partitioning, and direct-only behavior is
explicit; removing the contribution makes its typed context unavailable.
Cookie credentials, sessions, CORS topology, __Host- policy, and an environment-reading token
convenience remain deferred to the auth pack.
Docs show one authenticated typed-client call; root check/test/publish dry-run pass.
Boundaries
Not here: the scaffold protecting /api by default. The generated service template ships with
no auth option and a framework test codifies it
(packages/service/tests/auth/define-service-auth_test.ts:11-22) — that defect, the plugin add auth starter surface, and the CORS origin:'*' default all belong to the auth pack, not to
this issue.
Not here: making plugin services guardable.createPluginService has no auth option and
never calls withAuthn/withAuthz
(packages/plugin/src/service/presentation/create-plugin-service.ts) — auth pack.
Not here: the discarded Set-Cookie / outputStructure: 'detailed' defect or the
unauthenticated POST /api/v1/auth/signout — auth pack.
Do not implement the server-side authorizer that consumes policy.scopes — auth pack.
Do not add cookie/credentials: 'include' support until RFC-A Q1 is answered.
Docs/consumer proof
docs/site/identity-access/how-to/add-authentication.md and docs/site/services-sdk/sdk.md gain the
first authenticated typed-client example in the repo's history, and docs/site/tutorials/workspace/05-route-authz.md:248-258 swaps its curl for that example. Consumer
proof is that NetScript's own CLI stops hand-rolling fetch against the auth service — the deleted auth-session-client.ts request/parse code is the adoption evidence, and the two negative gates
prove the credential is actually load-bearing rather than decorative.
Provenance
Seed run plan-fable5-remediation-roadmap--seed, PR #1347, 2026-08-08. Sourced from research/repo-audit/auth.md (G1, and §9's ordering that names auth as the first dogfood) and research/repo-audit/services-sdk.md (S5); the absence of an authClient symbol and of any oRPC .meta() usage was re-verified by grep against worktree baseline fac9e339042c. No GitHub mutation
was performed.
Filed from planning seed PR #1347 · source Draft-ID T1-05 · live issue #1352.
Important
0.0.7 normative scope amendment — 2026-08-13. RFC 0001 Stage 4 supersedes conflicting rows
below. Ship the
@netscript/plugin-auth-core/sdkbearer credential contribution, access-metadatabehavior, secret redaction, partitioned/direct-only cache rules, plugin manifest reference, docs,
and explicit scaffold/app selection. Cookie/session transport does not land in this issue and
the canonical module path is
@netscript/plugin-auth-core/sdk. The contribution must composeonly through the Stage-2 public protocol and must not expose upstream oRPC identities.
Summary
@netscript/service/authreadsAuthorization: Bearer …andx-api-key, andcreateServiceClientcannot send either — the SDK has no concept of a credential at any layer.NetScript's own CLI proves the consequence: it calls the auth service with raw
fetchandhand-rolled JSON shape-sniffing rather than the typed client it already depends on. This issue makes
auth the first dogfood consumer of the RFC-A contribution chain: a first-party
authClient(…)/authContribution(…)that attaches credentials, reads procedure policy metadata, surfaces a definedcredential error, and is declared from the auth plugin's manifest — so the seam is validated by the
sharpest real consumer rather than by a toy.
Evidence
research/repo-audit/auth.md§0 (three independent proofs), §2 (the capability table),§4.2 (cross-origin +
__Host-cookie topology), §5 (no procedure policy metadata), gapsG1/G2/G8/G9/G10;
research/repo-audit/services-sdk.md§2.4 (S5);research/external/orpc.md§1.5, §4 (G1, G3).fac9e339042c(re-verified for this draft):packages/service/src/auth/static-credential-authenticator.ts:108-117— server readsAuthorization: Bearer …andx-api-key.packages/sdk/src/client/http-client-link.ts:82-101— the client's entire header authorship isContent-Typeplus optionaltraceparent/tracestate.grep -rn 'Authorization' packages/sdk/src→ no match.
packages/sdk/src/ports/service-client.ts:129-155,203-222— no credential field on the optionsrecord or on per-call context.
packages/cli/src/public/features/plugins/auth/auth-session-client.ts:7-23,27-37— thefirst-party CLI calls the auth service with raw
fetchand no credential; hardcoded URLs atauth-plugin-command.ts:87,98-100(the first is already broken — auth: session list --stream-url default pins localhost:4437 which no longer exists post-#1211 #1243).grep -rn 'authClient' packages plugins→ no such symbol exists; this issue creates it.packages/plugin/src/config/domain/plugin-contributions.ts:12-39— no client contribution group;:16is the closed-literal precedent to avoid.grep -rnE '\$meta<|\.meta\(' packages plugins→ no oRPC procedure metadata anywhere, sopolicy.publichas no current consumer to conflict with.packages/plugin-streams-core/src/application/stream-url-resolver.ts:136-150—getStreamsAuth()is the repo's only working credential header, built outside the typed client; existence proof
that a header seam fits this architecture.
[enterprise-auth S1]capability discovery,0.0.8), [enterprise-auth S13] Define organization-aware identity and authorization policy contracts #884 (org-aware policycontracts,
0.0.12), [enterprise-auth S14] Build an auth conformance, mocking, and scaffold test kit #885 (auth conformance kit,0.0.12), auth: session list --stream-url default pins localhost:4437 which no longer exists post-#1211 #1243 (broken CLI default URL,0.0.6), [frontend-contrib S20] Auth v1 frontend (account + session widget + signin starter) #942 (auth v1 frontend,0.0.11).Current surface
Server-side auth is real and correctly ordered —
withAuthn/withAuthzinstall before RPC routesmount, authz fails closed, and the principal reaches the oRPC handler context
(
research/repo-audit/auth.md§1.1). Client-side there is nothing: no credential option, noper-call override, no cookie forwarding, no emitter for the trusted-header authenticator that
packages/service/src/auth/trusted-header-authenticator.ts:32-54is waiting for. The docs cannotshow an authenticated typed call because none can be written — the authz tutorial can only show
curl -H 'authorization: Bearer read'(docs/site/tutorials/workspace/05-route-authz.md:248-258).Target contract
A first-party contribution shipped from the auth plugin, consumed through the RFC-A chain:
authContribution(options)declares{ auth: { token: string } }as per-call context, sooRPC's
ClientRestmakes it required at the call site — omitting it is a compile error, not a401. A server-only variant (
@netscript/plugin-auth/sdk/server) may close over a resolver thatreads a secret; the isomorphic descriptor never does.
authClient(...)is the convenience wrapper the CLI and generated apps use: acreateServiceClientpre-composed with the auth contribution againstauthContractV1, replacingthe raw-
fetchclient atpackages/cli/src/public/features/plugins/auth/auth-session-client.ts.NetScriptProcedureMeta.policy(RFC-A §3.6):it does not attach a credential to a
policy.publicprocedure, and it raises a definedCREDENTIAL_UNAVAILABLErather than sending an unauthenticated request to a non-public one.PluginContributionsclient group added by RFC-A — with a nameable, non-closed shape (contrastplugin-contributions.ts:16).x-api-keyland here. Cookie/sessiontransport does not —
research/repo-audit/auth.md§4.2 proves it cannot work across thecurrent cross-origin discovery +
__Host-prefix +origin:'*'CORS combination, and thetopology decision is the auth pack's.
Acceptance
descriptor contract; it does not own cookie/session transport or read environment variables.
the typed SDK path without a server-only import.
path is rejected, and absence of the contribution sends no credential.
invent a separate
policy.publicdialect.explicit; removing the contribution makes its typed context unavailable.
__Host-policy, and an environment-reading tokenconvenience remain deferred to the auth pack.
Boundaries
/apiby default. The generated service template ships withno
authoption and a framework test codifies it(
packages/service/tests/auth/define-service-auth_test.ts:11-22) — that defect, theplugin add authstarter surface, and the CORSorigin:'*'default all belong to the auth pack, not tothis issue.
createPluginServicehas noauthoption andnever calls
withAuthn/withAuthz(
packages/plugin/src/service/presentation/create-plugin-service.ts) — auth pack.Set-Cookie/outputStructure: 'detailed'defect or theunauthenticated
POST /api/v1/auth/signout— auth pack.no
tenantIdis added toPrincipal,AuthSession, or any contract here; the contributioncontext is merely extensible enough that [enterprise-auth S13] Define organization-aware identity and authorization policy contracts #884 can add one later.
gates above are this issue's own proof, not the kit.
session list --stream-urlpins a dead localhost port) — replacingthe CLI's transport here will touch that file; fix the URL under auth: session list --stream-url default pins localhost:4437 which no longer exists post-#1211 #1243 and reference it.
policy.scopes— auth pack.credentials: 'include'support until RFC-A Q1 is answered.Docs/consumer proof
docs/site/identity-access/how-to/add-authentication.mdanddocs/site/services-sdk/sdk.mdgain thefirst authenticated typed-client example in the repo's history, and
docs/site/tutorials/workspace/05-route-authz.md:248-258swaps itscurlfor that example. Consumerproof is that NetScript's own CLI stops hand-rolling
fetchagainst the auth service — the deletedauth-session-client.tsrequest/parse code is the adoption evidence, and the two negative gatesprove the credential is actually load-bearing rather than decorative.
Provenance
Seed run
plan-fable5-remediation-roadmap--seed, PR #1347, 2026-08-08. Sourced fromresearch/repo-audit/auth.md(G1, and §9's ordering that names auth as the first dogfood) andresearch/repo-audit/services-sdk.md(S5); the absence of anauthClientsymbol and of any oRPC.meta()usage was re-verified by grep against worktree baselinefac9e339042c. No GitHub mutationwas performed.
Filed from planning seed PR #1347 · source Draft-ID T1-05 · live issue #1352.