@agentproto/auth 0.2.0 → 1.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@agentproto/auth",
3
- "version": "0.2.0",
3
+ "version": "1.0.1",
4
4
  "description": "@agentproto/auth — AIP-50 AUTH.md reference implementation. Auth-provider doctype: how CLI tools and agents authenticate to API servers via a standardized discovery chain and pluggable flow engines, aligned to the WorkOS auth.md open standard.",
5
5
  "keywords": [
6
6
  "agentproto",
@@ -43,7 +43,7 @@
43
43
  },
44
44
  "dependencies": {
45
45
  "gray-matter": "^4.0.3",
46
- "zod": "^4.4.3",
46
+ "zod": "^4.5.4",
47
47
  "@agentproto/define-doctype": "0.1.1"
48
48
  },
49
49
  "devDependencies": {
@@ -1,131 +0,0 @@
1
- ---
2
- name: auth
3
- description:
4
- Authenticate an agentproto agent or MCP connector to a service via
5
- @agentproto/auth's credential broker — declare an auth provider
6
- (pat / service-auth / device-code), store the credential ONCE in a
7
- CredentialStore, and resolve fresh Authorization headers at call/connect
8
- time. Use to wire a Bearer/OAuth API (agentpush, a hosted MCP server, an
9
- internal service) into an agent WITHOUT putting secrets in env vars or
10
- .mcp.json.
11
- metadata:
12
- tags: agentproto, auth, aip-50, credentials, broker, mcp, secrets, bearer, oauth
13
- ---
14
-
15
- ## When to use
16
-
17
- Reach for this whenever an agent (or a child MCP it mounts) must present a
18
- credential to a remote service and you don't want that secret sprayed into the
19
- daemon's global env or hardcoded in a config file. The hallmark: "how do I give
20
- this agent access to `<service>` without leaking the key to every other agent?"
21
-
22
- - A tool/agent calls a Bearer API (agentpush, Stripe, an internal API).
23
- - A hosted/remote MCP server needs an `Authorization` header.
24
- - You want ONE place to store a key, scoped per service, resolved fresh (with
25
- refresh) at use-time instead of a long-lived env var.
26
-
27
- Do NOT use for the daemon's own tunnel login (that's `agentproto auth login`, a
28
- device-code flow already wired) — though it uses the same substrate underneath.
29
-
30
- ## The model — one source of truth, resolved on demand
31
-
32
- ```
33
- auth provider (declares WHERE/HOW) ──┐
34
- CredentialStore (holds the secret) ──┤─▶ CredentialBroker.resolveHeaders({ path, audience })
35
- │ → { Authorization: "Bearer …" } (fresh, per call)
36
- ```
37
-
38
- - **Provider** — a manifest declaring a service's `id`, `apiBase`, and `auth`
39
- flow. Config only, never the secret. Registered once (`registerAuthProvider`).
40
- - **CredentialStore** — where the secret lives: `KeychainStore` (macOS CLI),
41
- `FileStore` (AES-256-GCM, headless — key from `AGENTPROTO_STORE_KEY`),
42
- `MemoryStore` (tests). Swap the backend, same interface.
43
- - **Broker** — `resolveHeaders({ path, audience?, signal? })` turns a provider
44
- `path` into ready-to-use headers: serves a fresh stored bearer, else runs the
45
- flow. `audience` (`api` / `mcp` / `tunnel`) scopes the credential so it can't
46
- be reused cross-plane.
47
- - **Flows** — pick one per service: `pat` (static token you store/paste),
48
- `service-auth` (auth.md claim ceremony → short oat + durable assertion),
49
- `device-code` (RFC 8628 → durable daemon token + refresh).
50
-
51
- ## Recipe
52
-
53
- ### 1. Declare + register the provider
54
-
55
- TS literal (builtin/tests):
56
- ```ts
57
- import { defineAuthProvider, registerAuthProvider } from "@agentproto/auth"
58
-
59
- registerAuthProvider(defineAuthProvider({
60
- id: "agentpush",
61
- description: "AgentPush API — paste a personal API key.",
62
- apiBase: "https://api.agentpush.example",
63
- audience: "mcp", // or "api"
64
- auth: { flow: "pat", tokenStore: { keychain: "agentpush", account: "{server}" } },
65
- }))
66
- ```
67
- Or ship a vendor `*.auth.md` and `parseAuthProviderManifest(...)` → `registerAuthProvider(...)` — a host adds providers without editing this package.
68
-
69
- ### 2. Store the secret ONCE (out of env, into the store)
70
-
71
- ```ts
72
- import { KeychainStore, resolveStoreRef, getAuthProvider } from "@agentproto/auth"
73
-
74
- const p = getAuthProvider("agentpush")!
75
- const store = new KeychainStore() // or FileStore for headless
76
- await store.write(resolveStoreRef(p.auth.tokenStore, p.apiBase, p.audience),
77
- { value: process.env.AGENTPUSH_API_KEY!, kind: "pat" })
78
- ```
79
- Do this once (onboarding / a `secrets set` step) — then delete the env var.
80
-
81
- ### 3. Resolve at use-time
82
-
83
- ```ts
84
- import { CredentialBroker, getAuthProvider } from "@agentproto/auth"
85
-
86
- const broker = new CredentialBroker({ store, getProvider: getAuthProvider })
87
- const headers = await broker.resolveHeaders({ path: "agentpush", audience: "mcp" })
88
- // → { Authorization: "Bearer …" } — attach to your fetch / MCP transport
89
- ```
90
- Fresh every call; for `service-auth`/`device-code` it auto-refreshes. No secret
91
- touches env or `.mcp.json`.
92
-
93
- ## Two consumption paths
94
-
95
- **A. Agent calls the service in its own code/tool.** Works TODAY: resolve via the
96
- broker (step 3) and attach the header. Nothing else to wire.
97
-
98
- **B. Service exposed as a child MCP the agent mounts.** The clean target is a
99
- **`credentialRef`** on the child-mcp spec that the daemon resolves via the broker
100
- at connect-time (the `mcp-header` exposure pattern — `resolveMcpHeaderExposure`
101
- turns a `credentialPath` into headers via a structural resolver the broker
102
- satisfies). **Gap:** `agent_start.mcpServers` today carries only
103
- `{ name, ref, transport }` — no `headers`/`credentialRef` — so brokered auth
104
- can't yet reach a child MCP at mount. Until that plumbing lands, either use path
105
- A, or resolve the header at spawn and pass it through your own mount path.
106
-
107
- ## Worked example — agentpush
108
-
109
- agentpush uses a static Bearer key. Clean-auth wiring:
110
- 1. Register `agentpush` as a `pat` provider (step 1), `audience: "mcp"`.
111
- 2. Move `AGENTPUSH_API_KEY` from the daemon env into the store (step 2).
112
- 3. In-code callers resolve `broker.resolveHeaders({ path: "agentpush" })` (path A) —
113
- works now, key out of the global env, scoped to this agent.
114
- 4. For agentpush-as-child-MCP (path B), a `credentialRef: "agentpush"` on the
115
- child-mcp spec + daemon broker-resolve-at-connect is the north star (reuses
116
- everything here; needs the `agent_start.mcpServers` credentialRef plumbing).
117
-
118
- ## Common mistakes
119
-
120
- - **Storing the key in the daemon's global env** — every spawned agent inherits
121
- it. The whole point of the store is per-service, per-spawn scoping.
122
- - **Skipping `audience`** — set it (`api`/`mcp`/`tunnel`) so a credential minted
123
- for one plane can't be presented on another (defense-in-depth; the normative
124
- boundary is server-side).
125
- - **Caching `resolveHeaders` output** — resolve per call; the broker owns
126
- freshness/refresh. A cached header defeats `service-auth`/`device-code` refresh.
127
- - **`pat` where the service issues short-lived tokens** — use `service-auth`
128
- (mint + refresh) instead of pasting a token that expires.
129
- - **Wrong header shape** — `resolveHeaders` returns a header map; a service that
130
- wants `X-Api-Key` (not `Authorization`) needs the provider/flow to emit that
131
- shape, not a Bearer.