@keycardai/eve 0.2.0 → 0.4.0

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/README.md CHANGED
@@ -16,8 +16,9 @@ Three adapters, each one plugging into an eve primitive instead of wrapping it:
16
16
  pnpm add @keycardai/eve
17
17
  ```
18
18
 
19
- `eve` is a peer dependency, pinned to `>=0.54.3 <0.55.0`. This package was
20
- built and verified against eve `0.54.3`. eve is in public beta and ships
19
+ `eve` is a peer dependency, pinned to `>=0.71.3 <0.72.0`: this package
20
+ requires eve 0.71 and was built and verified against eve `0.71.3`. eve is in
21
+ public beta and ships
21
22
  releases most days, and its connection and auth surfaces are still moving, so
22
23
  the range deliberately stops at the next minor rather than tracking `^`. Widen
23
24
  it only after re-running this package's tests against the newer eve.
@@ -27,7 +28,15 @@ range current: a consumer who runs a newer eve and installs this anyway —
27
28
  `--legacy-peer-deps` — silently loses the check, and the incompatibilities
28
29
  surface at build time instead. Two of them are what the 0.47 → 0.54 bump had to
29
30
  fix: an `auth` key list that `displayName` is not in, and a `requireAuth`
30
- options type with no `reason` field.
31
+ options type with no `reason` field. The 0.54 → 0.71 bump moved non-interactive
32
+ connection auth from `principalType` to `credentialOwner`.
33
+
34
+ Upgrading an agent across eve 0.70 signs Slack users in once more: eve changed
35
+ the Slack principal to `slack:<install team>:<user>`, and this package keys
36
+ user-scoped tokens and grants by that principal, so the entries stored under the
37
+ old principal are no longer found. Nothing else about the integration moves
38
+ with the upgrade; the per-attempt callback
39
+ (`/eve/v1/connections/:name/callback/:attemptId/:token`) is unchanged.
31
40
 
32
41
  eve itself declares `engines.node: ">=24"` and is ESM only. This package
33
42
  imports eve for types only (`import type { ... } from "eve/connections"`), so
@@ -106,6 +115,11 @@ export default defineMcpClientConnection({
106
115
  the connection app-scoped; a function receives the connection principal and
107
116
  makes it user-scoped.
108
117
 
118
+ Each factory declares eve 0.71's `credentialOwner` (`"app"` or `"user"`) for
119
+ the pattern it implements, which is how eve decides whether to cache the token
120
+ once per connection or once per connection principal. Interactive definitions
121
+ (below) keep eve's `principalType: "user"`.
122
+
109
123
  Nothing falls back to the agent's authority. A user-pattern connection with no
110
124
  user principal, a turn whose subject token was never retained, and an expired
111
125
  subject token all fail, each with its own reason: `principal_required`,
@@ -154,23 +168,23 @@ export default defineMcpClientConnection({
154
168
  ```
155
169
 
156
170
  **There is no `clientId`, and adding one usually breaks the flow.** eve mints a
157
- fresh callback URL for every attempt — `/eve/v1/connections/:name/callback/
158
- :attemptId/:token` — while [RFC 9700][rfc9700] requires the authorization server
159
- to match `redirect_uri` against the client's registered list by exact string
160
- comparison. A client registered ahead of time cannot name a URL that is
161
- generated later, so the request is rejected with something like
162
- `Unauthorized redirect URI`. Leaving `clientId` unset registers a client per
163
- attempt instead (RFC 7591), whose single redirect URI is the callback that
164
- attempt will actually return to. Each client is public and PKCE-bound, so
165
- nothing secret enters eve's durable resume state; if the server issues a
166
- confidential client anyway, the attempt is abandoned rather than journaling a
167
- secret.
171
+ fresh callback URL for every attempt
172
+ (`/eve/v1/connections/:name/callback/:attemptId/:token`) while
173
+ [RFC 9700][rfc9700] requires the authorization server to match `redirect_uri`
174
+ against the client's registered list by exact string comparison. A client
175
+ registered ahead of time cannot name a URL that is generated later, so the
176
+ request is rejected with something like `Unauthorized redirect URI`. Leaving
177
+ `clientId` unset registers a client per attempt instead (RFC 7591), whose
178
+ single redirect URI is the callback that attempt will return to. Each client is
179
+ public and PKCE-bound, so nothing secret enters eve's durable resume state; if
180
+ the server issues a confidential client anyway, the attempt is abandoned rather
181
+ than journaling a secret.
168
182
 
169
183
  Set `clientId` only when that client's registered redirect URIs already cover
170
184
  eve's callback. Note that a Keycard application `identifier` is not a client id:
171
- zones identify clients by [Client ID Metadata Document][cimd] — an HTTPS URL
172
- with a path, serving the client's metadata — so a value like
173
- `urn:app:my-agent` fails with `Unsupported client identifier prefix: urn`.
185
+ zones identify clients by [Client ID Metadata Document][cimd], an HTTPS URL
186
+ with a path serving the client's metadata, so a value like `urn:app:my-agent`
187
+ fails with `Unsupported client identifier prefix: urn`.
174
188
 
175
189
  Per-attempt clients accumulate in the zone. They hold no secret and their
176
190
  callback is single-use, but a server returning `registration_client_uri` and
@@ -182,17 +196,20 @@ callback is single-use, but a server returning `registration_client_uri` and
182
196
  The definition implements the same three-method form as eve's
183
197
  `defineInteractiveAuthorization`, over `@keycardai/oauth`'s v3 web-app flow:
184
198
 
185
- - `getToken` returns a token only when this package holds one for the
186
- principal. Otherwise it throws `ConnectionAuthorizationRequiredError`, so eve
187
- emits `authorization.required`, runs `startAuthorization` in a durable step,
188
- and parks the turn on a framework-owned callback.
199
+ - `getToken` looks up the principal's stored grants and returns the access
200
+ token of one whose resources cover this connection's `resource` and whose
201
+ scopes cover `requestScopes`. Within 60 seconds of expiry, a grant holding a
202
+ refresh token is refreshed first (see below). With no usable grant it throws
203
+ `ConnectionAuthorizationRequiredError`, so eve emits
204
+ `authorization.required`, runs `startAuthorization` in a durable step, and
205
+ parks the turn on a framework-owned callback.
189
206
  - `startAuthorization` registers this attempt's client (unless `clientId` is
190
207
  set), calls `beginAuthorization` for the connection's resource list against
191
208
  eve's minted callback URL, and returns the challenge URL plus the `state`,
192
209
  PKCE verifier and client id as JSON resume state.
193
210
  - `completeAuthorization` calls `completeAuthorization` with eve's callback
194
211
  params and the journaled resume state, redeeming as the client that attempt's
195
- authorization request ran as, and hands eve the token.
212
+ authorization request ran as, and stores the resulting grant.
196
213
 
197
214
  **Resume without authorization cannot yield a credential.** `getToken` is the
198
215
  only path that returns a token, and it reads a store only
@@ -204,6 +221,72 @@ an authorization has settled ends the tool call. User denial is reported as
204
221
  `ConnectionAuthorizationFailedError` with `reason: "access_denied"` and
205
222
  `retryable: false`, so eve stops re-prompting.
206
223
 
224
+ ### Grants: what is stored, and for how long
225
+
226
+ `completeAuthorization` stores a grant, not a bare token: the access token and
227
+ its expiry, the refresh token the zone returned, the client id the grant was
228
+ issued to, and the resources and scopes granted. Grants are keyed by the
229
+ principal, never by `connectionName`, which is display and error text only;
230
+ two `Keycard.interactive()` definitions in one process with the same
231
+ `connectionName` fail at definition time with
232
+ `AuthProviderConfigurationError`. Because a grant is matched on what it covers,
233
+ a connection listing the agent's other resources in `additionalResources`
234
+ yields one sign-in that serves every connection whose resource is in the list.
235
+
236
+ When a grant is within 60 seconds of expiry and holds a refresh token,
237
+ `getToken` posts `grant_type=refresh_token` to the zone as the grant's own
238
+ client (public, no secret; a per-attempt client registers with
239
+ `refresh_token` among its grant types), stores the rotated access and refresh
240
+ token pair, and returns the new access token without parking. A refresh the
241
+ zone refuses with `invalid_grant` deletes the grant and throws `Required`, so
242
+ the turn parks for a fresh sign-in. A transport or 5xx failure keeps the grant
243
+ and fails the tool call with `retryable: true`. A grant without a refresh token
244
+ parks at expiry, as before.
245
+
246
+ `evict` removes every grant of the principal that covers this connection's
247
+ resource, leaving grants for other resources in place.
248
+
249
+ ### Plugging a durable grant store
250
+
251
+ The default store is process-local, so a restarted agent parks once more for
252
+ each user. To keep grants across processes, pass `tokens` an object of this
253
+ shape:
254
+
255
+ ```ts
256
+ import type { AuthorizedGrant, GrantStore } from "@keycardai/eve";
257
+
258
+ export function redisGrantStore(redis: {
259
+ hgetall(key: string): Promise<Record<string, string>>;
260
+ hset(key: string, field: string, value: string): Promise<unknown>;
261
+ hdel(key: string, field: string): Promise<unknown>;
262
+ }): GrantStore {
263
+ const key = (principal: string) => `keycard:grants:${principal}`;
264
+ return {
265
+ async list(principal) {
266
+ const rows = await redis.hgetall(key(principal));
267
+ return Object.values(rows).map((row) => JSON.parse(row) as AuthorizedGrant);
268
+ },
269
+ async put(principal, grant) {
270
+ await redis.hset(key(principal), grant.id, JSON.stringify(grant));
271
+ },
272
+ async remove(principal, grantId) {
273
+ await redis.hdel(key(principal), grantId);
274
+ },
275
+ };
276
+ }
277
+ ```
278
+
279
+ Every method is async, and `put` with an `id` already held replaces that grant
280
+ (a refresh rewrites the rotated pair under the same `id`). The same three
281
+ methods map onto Upstash Redis's `hgetall`, `hset` and `hdel`, or any other
282
+ key-value backend.
283
+
284
+ Choosing a durable store puts refresh tokens at rest in that backend. Each one
285
+ is a long-lived credential for the user's resources, so the backend's access
286
+ control and encryption are yours to provide. This package never writes a grant
287
+ into eve's session attributes for that reason: a refresh token must not enter
288
+ eve's durable state.
289
+
207
290
  ## Parity with `@keycardai/langchain`
208
291
 
209
292
  The two packages implement the same Keycard access model against different
@@ -247,8 +330,8 @@ const auth = Keycard.onBehalfOf({
247
330
  `fakeZoneClient()` records every exchange, impersonation, and client
248
331
  credentials call, and can fail one resource or every request. `keycardAuth()`
249
332
  takes a `verify` seam in place of the JWKS-backed verifier, and
250
- `Keycard.interactive()` takes a `flow` seam in place of the web-flow calls —
251
- `begin`, `complete`, and the `register` used for per-attempt clients. A flow
333
+ `Keycard.interactive()` takes a `flow` seam in place of the web-flow calls:
334
+ `begin`, `complete`, `register` for per-attempt clients, and `refresh`. A flow
252
335
  without `register` is rejected at construction unless a `clientId` is also
253
336
  given, so a test cannot accidentally exercise a combination that cannot work in
254
337
  production. An injected `client` or `flow` supersedes `zoneUrl`, so a test needs
@@ -1,25 +1,28 @@
1
- import type { ConnectionPrincipal, NonInteractiveAuthorizationDefinition } from "eve/connections";
1
+ import type { ConnectionPrincipal, CredentialOwner, NonInteractiveAuthorizationDefinition } from "eve/connections";
2
2
  import { type KeycardConnectionOptions } from "./config.js";
3
3
  /**
4
- * NONE OF THESE DEFINITIONS CARRY A `displayName`, and adding one back breaks
5
- * every connection that uses them.
6
- *
7
- * eve validates an authored connection's `auth` against a closed key list —
8
- * `completeAuthorization`, `evict`, `getToken`, `principalType`,
9
- * `startAuthorization`, `vercelConnect` — and `displayName` is not in it, so a
10
- * definition carrying one fails the BUILD with
11
- * `The "auth" field Unknown key "displayName"`. That is an inconsistency inside
12
- * eve rather than a rule: its `normalizeAuthorizationSpec` accepts and forwards
13
- * the field, and only the authored-module key check disagrees. Until the two
14
- * agree, a package whose whole purpose is to be dropped into `auth:` has to
15
- * keep off the key.
16
- *
17
- * Nothing is lost. The only consumer of a definition-level `displayName` is
18
- * eve's `stampChallengeDisplayName`, which resolves
19
- * `definition.displayName ?? challenge.displayName` — so a name supplied on the
20
- * challenge still reaches the sign-in prompt (see {@link interactive}), and a
21
- * non-interactive definition has no challenge to name in the first place. Tools
22
- * name a provider through `ToolAuthOptions.displayName` at the call site.
4
+ * A non-interactive connection auth definition as eve 0.71 accepts it:
5
+ * `credentialOwner` declares whether the credential belongs to the agent
6
+ * (`"app"`, one token per connection across sessions) or to the end user
7
+ * (`"user"`, one token per connection principal). eve deprecated
8
+ * `principalType` on non-interactive auth in favor of it; interactive
9
+ * definitions still use `principalType: "user"`.
10
+ */
11
+ export type KeycardConnectionAuth = Omit<NonInteractiveAuthorizationDefinition, "principalType"> & {
12
+ readonly credentialOwner: CredentialOwner;
13
+ };
14
+ /**
15
+ * None of these definitions carry a `displayName`. eve validates an authored
16
+ * connection's `auth` against a closed key list (`completeAuthorization`,
17
+ * `credentialOwner`, `evict`, `getToken`, `principalType`,
18
+ * `startAuthorization`, `vercelConnect`),
19
+ * and a definition carrying any other key fails the build with
20
+ * `The "auth" field Unknown key "displayName"`. The only consumer of the field
21
+ * is eve's `stampChallengeDisplayName`, which resolves
22
+ * `definition.displayName ?? challenge.displayName`, so an interactive
23
+ * definition names itself on the challenge instead (see {@link interactive}),
24
+ * a non-interactive one has no challenge to name, and tools name a provider
25
+ * through `ToolAuthOptions.displayName` at the call site.
23
26
  */
24
27
  /** Options for {@link impersonate}. */
25
28
  export interface KeycardImpersonateOptions extends KeycardConnectionOptions {
@@ -36,7 +39,7 @@ export interface KeycardImpersonateOptions extends KeycardConnectionOptions {
36
39
  * user, so this works on schedules and subagent turns. No exchange and no
37
40
  * impersonation, so nothing about the caller reaches the zone.
38
41
  */
39
- export declare function asSelf(options: KeycardConnectionOptions): NonInteractiveAuthorizationDefinition;
42
+ export declare function asSelf(options: KeycardConnectionOptions): KeycardConnectionAuth;
40
43
  /**
41
44
  * Connection auth that exchanges the caller's token for a resource token.
42
45
  *
@@ -52,7 +55,7 @@ export declare function asSelf(options: KeycardConnectionOptions): NonInteractiv
52
55
  * the sign-in signal, decided by a decode-only expiry check so an already
53
56
  * dead token never costs an exchange round trip.
54
57
  */
55
- export declare function onBehalfOf(options: KeycardConnectionOptions): NonInteractiveAuthorizationDefinition;
58
+ export declare function onBehalfOf(options: KeycardConnectionOptions): KeycardConnectionAuth;
56
59
  /**
57
60
  * Connection auth that acts for a named user the agent holds no token for.
58
61
  *
@@ -65,5 +68,5 @@ export declare function onBehalfOf(options: KeycardConnectionOptions): NonIntera
65
68
  * `principal_required` rejection; a fixed identifier needs no caller, so the
66
69
  * connection is app-scoped and runs on schedules.
67
70
  */
68
- export declare function impersonate(options: KeycardImpersonateOptions): NonInteractiveAuthorizationDefinition;
71
+ export declare function impersonate(options: KeycardImpersonateOptions): KeycardConnectionAuth;
69
72
  //# sourceMappingURL=connections.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"connections.d.ts","sourceRoot":"","sources":["../../src/connections.ts"],"names":[],"mappings":"AAOA,OAAO,KAAK,EACV,mBAAmB,EACnB,qCAAqC,EAEtC,MAAM,iBAAiB,CAAC;AAEzB,OAAO,EAAsC,KAAK,wBAAwB,EAAE,MAAM,aAAa,CAAC;AAKhG;;;;;;;;;;;;;;;;;;;;GAoBG;AAEH,uCAAuC;AACvC,MAAM,WAAW,yBAA0B,SAAQ,wBAAwB;IACzE;;;OAGG;IACH,cAAc,EAAE,MAAM,GAAG,CAAC,CAAC,SAAS,EAAE,mBAAmB,KAAK,MAAM,CAAC,CAAC;CACvE;AAED;;;;;;GAMG;AACH,wBAAgB,MAAM,CACpB,OAAO,EAAE,wBAAwB,GAChC,qCAAqC,CAkBvC;AAED;;;;;;;;;;;;;;GAcG;AACH,wBAAgB,UAAU,CACxB,OAAO,EAAE,wBAAwB,GAChC,qCAAqC,CAkDvC;AAED;;;;;;;;;;;GAWG;AACH,wBAAgB,WAAW,CACzB,OAAO,EAAE,yBAAyB,GACjC,qCAAqC,CAsCvC"}
1
+ {"version":3,"file":"connections.d.ts","sourceRoot":"","sources":["../../src/connections.ts"],"names":[],"mappings":"AAOA,OAAO,KAAK,EACV,mBAAmB,EACnB,eAAe,EACf,qCAAqC,EAEtC,MAAM,iBAAiB,CAAC;AAEzB,OAAO,EAAsC,KAAK,wBAAwB,EAAE,MAAM,aAAa,CAAC;AAKhG;;;;;;;GAOG;AACH,MAAM,MAAM,qBAAqB,GAAG,IAAI,CACtC,qCAAqC,EACrC,eAAe,CAChB,GAAG;IACF,QAAQ,CAAC,eAAe,EAAE,eAAe,CAAC;CAC3C,CAAC;AAEF;;;;;;;;;;;;GAYG;AAEH,uCAAuC;AACvC,MAAM,WAAW,yBAA0B,SAAQ,wBAAwB;IACzE;;;OAGG;IACH,cAAc,EAAE,MAAM,GAAG,CAAC,CAAC,SAAS,EAAE,mBAAmB,KAAK,MAAM,CAAC,CAAC;CACvE;AAED;;;;;;GAMG;AACH,wBAAgB,MAAM,CACpB,OAAO,EAAE,wBAAwB,GAChC,qBAAqB,CAkBvB;AAED;;;;;;;;;;;;;;GAcG;AACH,wBAAgB,UAAU,CACxB,OAAO,EAAE,wBAAwB,GAChC,qBAAqB,CAkDvB;AAED;;;;;;;;;;;GAWG;AACH,wBAAgB,WAAW,CACzB,OAAO,EAAE,yBAAyB,GACjC,qBAAqB,CAsCvB"}
@@ -13,7 +13,7 @@ import { principalKey, readSubjectToken } from "./subjectTokens.js";
13
13
  export function asSelf(options) {
14
14
  const config = resolveConnectionConfig(options, "asSelf");
15
15
  return {
16
- principalType: "app",
16
+ credentialOwner: "app",
17
17
  async getToken() {
18
18
  const request = {
19
19
  resource: config.resource,
@@ -42,7 +42,7 @@ export function asSelf(options) {
42
42
  export function onBehalfOf(options) {
43
43
  const config = resolveConnectionConfig(options, "onBehalfOf");
44
44
  return {
45
- principalType: "user",
45
+ credentialOwner: "user",
46
46
  async getToken({ principal }) {
47
47
  requireUser(principal, config.connectionName);
48
48
  const subjectToken = readSubjectToken(principal, config.subjectTokens);
@@ -100,7 +100,7 @@ export function impersonate(options) {
100
100
  throw new AuthProviderConfigurationError("impersonate requires a non-empty user identifier");
101
101
  }
102
102
  return {
103
- principalType: typeof identifier === "function" ? "user" : "app",
103
+ credentialOwner: typeof identifier === "function" ? "user" : "app",
104
104
  async getToken({ principal }) {
105
105
  let userIdentifier;
106
106
  if (typeof identifier === "function") {
@@ -1 +1 @@
1
- {"version":3,"file":"connections.js","sourceRoot":"","sources":["../../src/connections.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"connections.js","sourceRoot":"","sources":["../../src/connections.ts"],"names":[],"mappings":"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"}
@@ -17,9 +17,9 @@
17
17
  export { keycardAuth } from "./auth.js";
18
18
  export type { KeycardAuthOptions, SubjectTokenRetention } from "./auth.js";
19
19
  export { asSelf, impersonate, onBehalfOf } from "./connections.js";
20
- export type { KeycardImpersonateOptions } from "./connections.js";
20
+ export type { KeycardConnectionAuth, KeycardImpersonateOptions } from "./connections.js";
21
21
  export { interactive, memoryAuthorizedTokenStore } from "./interactive.js";
22
- export type { AuthorizedToken, AuthorizedTokenStore, KeycardInteractiveOptions, KeycardResumeState, RegisterAttemptClientOptions, RegisteredClient, WebAppFlow, } from "./interactive.js";
22
+ export type { AuthorizedGrant, GrantStore, KeycardInteractiveOptions, KeycardResumeState, RegisterAttemptClientOptions, RegisteredClient, WebAppFlow, } from "./interactive.js";
23
23
  export type { KeycardConnectionOptions } from "./config.js";
24
24
  export { AuthorizationFailedError, AuthorizationRequiredError, FailureReason, RouteRejectedError, } from "./errors.js";
25
25
  export { decodeClaims, subjectTokenExpired } from "./expiry.js";
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AACH,OAAO,EAAE,WAAW,EAAE,MAAM,WAAW,CAAC;AACxC,YAAY,EAAE,kBAAkB,EAAE,qBAAqB,EAAE,MAAM,WAAW,CAAC;AAE3E,OAAO,EAAE,MAAM,EAAE,WAAW,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAC;AACnE,YAAY,EAAE,yBAAyB,EAAE,MAAM,kBAAkB,CAAC;AAElE,OAAO,EAAE,WAAW,EAAE,0BAA0B,EAAE,MAAM,kBAAkB,CAAC;AAC3E,YAAY,EACV,eAAe,EACf,oBAAoB,EACpB,yBAAyB,EACzB,kBAAkB,EAClB,4BAA4B,EAC5B,gBAAgB,EAChB,UAAU,GACX,MAAM,kBAAkB,CAAC;AAE1B,YAAY,EAAE,wBAAwB,EAAE,MAAM,aAAa,CAAC;AAE5D,OAAO,EACL,wBAAwB,EACxB,0BAA0B,EAC1B,aAAa,EACb,kBAAkB,GACnB,MAAM,aAAa,CAAC;AAErB,OAAO,EAAE,YAAY,EAAE,mBAAmB,EAAE,MAAM,aAAa,CAAC;AAEhE,OAAO,EAAE,yBAAyB,EAAE,MAAM,kBAAkB,CAAC;AAC7D,YAAY,EAAE,kBAAkB,EAAE,MAAM,kBAAkB,CAAC;AAE3D,OAAO,EACL,wBAAwB,EACxB,uBAAuB,EACvB,uBAAuB,GACxB,MAAM,oBAAoB,CAAC;AAC5B,YAAY,EAAE,iBAAiB,EAAE,MAAM,oBAAoB,CAAC;AAE5D,OAAO,EAAE,iBAAiB,EAAE,MAAM,iBAAiB,CAAC;AACpD,YAAY,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAC;AAElD,OAAO,EAAE,MAAM,EAAE,WAAW,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAC;AACnE,OAAO,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAC;AAE/C;;;GAGG;AACH,eAAO,MAAM,OAAO;;;;;EAKlB,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AACH,OAAO,EAAE,WAAW,EAAE,MAAM,WAAW,CAAC;AACxC,YAAY,EAAE,kBAAkB,EAAE,qBAAqB,EAAE,MAAM,WAAW,CAAC;AAE3E,OAAO,EAAE,MAAM,EAAE,WAAW,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAC;AACnE,YAAY,EAAE,qBAAqB,EAAE,yBAAyB,EAAE,MAAM,kBAAkB,CAAC;AAEzF,OAAO,EAAE,WAAW,EAAE,0BAA0B,EAAE,MAAM,kBAAkB,CAAC;AAC3E,YAAY,EACV,eAAe,EACf,UAAU,EACV,yBAAyB,EACzB,kBAAkB,EAClB,4BAA4B,EAC5B,gBAAgB,EAChB,UAAU,GACX,MAAM,kBAAkB,CAAC;AAE1B,YAAY,EAAE,wBAAwB,EAAE,MAAM,aAAa,CAAC;AAE5D,OAAO,EACL,wBAAwB,EACxB,0BAA0B,EAC1B,aAAa,EACb,kBAAkB,GACnB,MAAM,aAAa,CAAC;AAErB,OAAO,EAAE,YAAY,EAAE,mBAAmB,EAAE,MAAM,aAAa,CAAC;AAEhE,OAAO,EAAE,yBAAyB,EAAE,MAAM,kBAAkB,CAAC;AAC7D,YAAY,EAAE,kBAAkB,EAAE,MAAM,kBAAkB,CAAC;AAE3D,OAAO,EACL,wBAAwB,EACxB,uBAAuB,EACvB,uBAAuB,GACxB,MAAM,oBAAoB,CAAC;AAC5B,YAAY,EAAE,iBAAiB,EAAE,MAAM,oBAAoB,CAAC;AAE5D,OAAO,EAAE,iBAAiB,EAAE,MAAM,iBAAiB,CAAC;AACpD,YAAY,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAC;AAElD,OAAO,EAAE,MAAM,EAAE,WAAW,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAC;AACnE,OAAO,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAC;AAE/C;;;GAGG;AACH,eAAO,MAAM,OAAO;;;;;EAKlB,CAAC"}
@@ -1,16 +1,13 @@
1
- import { type AuthorizationRedirect, type BeginAuthorizationOptions, type CompleteAuthorizationOptions, type TokenResponse } from "@keycardai/oauth";
1
+ import { type AuthorizationRedirect, type BeginAuthorizationOptions, type CompleteAuthorizationOptions, type RefreshAuthorizationOptions, type TokenResponse } from "@keycardai/oauth";
2
2
  import type { InteractiveAuthorizationDefinition, JsonValue } from "eve/connections";
3
3
  /**
4
4
  * The state journaled between eve's begin and callback steps.
5
5
  *
6
6
  * Every field is JSON, so the value satisfies eve's `JsonValue` bound and
7
- * survives the durable step boundary the park crosses.
8
- *
9
- * `clientId` is journaled because it is not necessarily the same value across
10
- * attempts: under per-attempt registration each authorization runs as its own
11
- * client, and the code can only be redeemed by the client the authorization
12
- * request was made with. Nothing secret is journaled — registered clients are
13
- * public and PKCE-bound; see {@link interactive}.
7
+ * survives the durable step boundary the park crosses. `clientId` is journaled
8
+ * because each attempt may run as its own registered client, and only that
9
+ * client can redeem the code. Nothing secret is journaled: registered clients
10
+ * are public and PKCE-bound (see {@link interactive}).
14
11
  */
15
12
  export interface KeycardResumeState {
16
13
  readonly state: string;
@@ -20,25 +17,38 @@ export interface KeycardResumeState {
20
17
  readonly clientId: string;
21
18
  readonly [key: string]: JsonValue;
22
19
  }
23
- /** A token this package minted for one principal, plus its advisory expiry. */
24
- export interface AuthorizedToken {
25
- readonly token: string;
20
+ /**
21
+ * A completed authorization for one principal.
22
+ *
23
+ * `resources` and `scopes` are what the zone granted, and decide which
24
+ * connections the grant serves. `clientId` is the client the grant was issued
25
+ * to, and the client a refresh runs as. `id` is stable across refreshes, so a
26
+ * store can replace the rotated pair in place.
27
+ */
28
+ export interface AuthorizedGrant {
29
+ readonly id: string;
30
+ readonly accessToken: string;
26
31
  readonly expiresAt?: number;
27
- readonly providerSubject?: string;
32
+ readonly refreshToken?: string;
33
+ readonly clientId: string;
34
+ readonly resources: readonly string[];
35
+ readonly scopes: readonly string[];
28
36
  }
29
37
  /**
30
- * Where completed authorizations live between turns.
38
+ * Where completed grants live between turns, keyed by principal.
31
39
  *
32
- * eve caches a resolved bearer for the duration of a step, and reruns
33
- * `getToken` after that. This store is what makes a second step reuse the
34
- * grant a user already completed instead of parking the turn again. The
35
- * default is process-local, so a fresh process re-parks rather than
36
- * resurrecting a credential from durable state.
40
+ * eve caches a resolved bearer for the duration of a step and reruns
41
+ * `getToken` after that; this store is what makes a later step reuse the grant
42
+ * a user already completed instead of parking again. `put` with an `id` the
43
+ * store already holds replaces that grant. The default is process-local, so a
44
+ * fresh process re-parks. A durable implementation (Redis, Upstash Redis) keeps the
45
+ * grant, refresh token included, at rest in that backend; eve's session
46
+ * attributes are never used, so no credential enters eve's durable state.
37
47
  */
38
- export interface AuthorizedTokenStore {
39
- get(key: string): AuthorizedToken | undefined;
40
- set(key: string, token: AuthorizedToken): void;
41
- delete(key: string): void;
48
+ export interface GrantStore {
49
+ list(principal: string): Promise<readonly AuthorizedGrant[]>;
50
+ put(principal: string, grant: AuthorizedGrant): Promise<void>;
51
+ remove(principal: string, grantId: string): Promise<void>;
42
52
  }
43
53
  /** What one authorization attempt needs its own OAuth client for. */
44
54
  export interface RegisterAttemptClientOptions {
@@ -67,6 +77,11 @@ export interface WebAppFlow {
67
77
  * `clientId` is configured, and unused when one is.
68
78
  */
69
79
  register?(options: RegisterAttemptClientOptions): Promise<RegisteredClient>;
80
+ /**
81
+ * Refreshes a grant at the token endpoint. When absent, a grant near expiry
82
+ * parks for a fresh sign-in instead.
83
+ */
84
+ refresh?(options: RefreshAuthorizationOptions): Promise<TokenResponse>;
70
85
  }
71
86
  export interface KeycardInteractiveOptions {
72
87
  /** The resource URL the authorization is scoped to. */
@@ -76,18 +91,16 @@ export interface KeycardInteractiveOptions {
76
91
  /**
77
92
  * OAuth client the browser flow runs as.
78
93
  *
79
- * OMIT THIS unless the client's registered redirect URIs already cover eve's
80
- * callback. eve mints a fresh callback URL per attempt — the route is
81
- * `/eve/v1/connections/:name/callback/:attemptId/:token` — while RFC 9700
94
+ * Leave this unset unless the client's registered redirect URIs already
95
+ * cover eve's callback. eve mints a fresh callback URL per attempt
96
+ * (`/eve/v1/connections/:name/callback/:attemptId/:token`) while RFC 9700
82
97
  * requires the authorization server to match `redirect_uri` by exact string
83
- * comparison. A statically registered client therefore cannot name the URL
84
- * the next attempt will use, and the request is rejected. Leaving this unset
85
- * registers the client per attempt instead, which is the only arrangement
86
- * that satisfies both.
98
+ * comparison, so a statically registered client cannot name the URL the next
99
+ * attempt will use. Unset, the client is registered per attempt instead.
87
100
  *
88
- * A Keycard application `identifier` is NOT a client id. Zones identify
89
- * clients by Client ID Metadata Document — an HTTPS URL with a path that
90
- * serves the client's metadata — so a value like `urn:app:my-agent` fails
101
+ * A Keycard application `identifier` is not a client id. Zones identify
102
+ * clients by Client ID Metadata Document, an HTTPS URL with a path that
103
+ * serves the client's metadata, so a value like `urn:app:my-agent` fails
91
104
  * with `Unsupported client identifier prefix: urn`.
92
105
  */
93
106
  clientId?: string;
@@ -99,65 +112,77 @@ export interface KeycardInteractiveOptions {
99
112
  */
100
113
  clientName?: string;
101
114
  /**
102
- * Initial access token (RFC 7591 §3.1) for a zone whose registration
115
+ * Initial access token (RFC 7591 section 3.1) for a zone whose registration
103
116
  * endpoint is authenticated. Unset for an open registration endpoint.
104
117
  */
105
118
  initialAccessToken?: string;
106
- /** Scopes requested in the authorization request. */
119
+ /**
120
+ * Scopes requested in the authorization request, and the scopes a stored
121
+ * grant must cover to serve this connection.
122
+ */
107
123
  requestScopes?: string | readonly string[];
108
- /** Extra resources authorized alongside `resource`. */
124
+ /**
125
+ * Extra resources authorized alongside `resource`. The resulting grant
126
+ * serves every connection whose resource it covers.
127
+ */
109
128
  additionalResources?: readonly string[];
110
- /** Name used in error messages and eve's authorization events. */
129
+ /**
130
+ * Name used in the challenge, error messages and eve's authorization
131
+ * events. Display text only, never a store key; two definitions in one
132
+ * process may not share it.
133
+ */
111
134
  connectionName?: string;
112
- /** Store for completed authorizations. Defaults to a process-local store. */
113
- tokens?: AuthorizedTokenStore;
135
+ /** Store for completed grants. Defaults to a process-local store. */
136
+ tokens?: GrantStore;
114
137
  /** Web-flow seam. Replaces the zone calls, so tests take no network. */
115
138
  flow?: WebAppFlow;
116
139
  }
140
+ /** Forgets every defined connection name. For tests that define many. */
141
+ export declare function resetInteractiveDefinitions(): void;
117
142
  /**
118
143
  * Interactive connection auth backed by the zone's web authorization flow.
119
144
  *
120
145
  * The three callbacks eve drives:
121
146
  *
122
- * - `getToken` returns a token only when this package holds one for the
123
- * principal. Otherwise it throws `ConnectionAuthorizationRequiredError`, and
124
- * eve emits `authorization.required`, runs `startAuthorization` in a durable
125
- * step, and parks the turn on its own callback webhook.
126
- * - `startAuthorization` begins the authorization-code flow with PKCE for the
127
- * connection's resources, against eve's minted callback URL, and returns the
128
- * challenge URL plus the `state` and verifier as resume state.
129
- * - `completeAuthorization` redeems the callback against the journaled resume
130
- * state and hands eve the token.
147
+ * - `getToken` returns a token when the store holds a grant for the principal
148
+ * whose resources cover this connection's resource and whose scopes cover
149
+ * `requestScopes`, refreshing it first when it is near expiry and holds a
150
+ * refresh token. Otherwise it throws `ConnectionAuthorizationRequiredError`,
151
+ * and eve emits `authorization.required`, runs `startAuthorization` in a
152
+ * durable step, and parks the turn on its own callback webhook.
153
+ * - `startAuthorization` registers the attempt's client, begins the
154
+ * authorization-code flow with PKCE for the connection's resources against
155
+ * eve's minted callback URL, and returns the challenge URL plus the state,
156
+ * verifier, resources, callback URL and client id as resume state.
157
+ * - `completeAuthorization` redeems the callback as the journaled client and
158
+ * stores the resulting grant.
131
159
  *
132
- * Resuming without a completed authorization cannot yield a credential.
133
- * `getToken` is the only path that returns a token and it reads the store,
134
- * which only `completeAuthorization` writes; a denied, mismatched, or failed
135
- * callback writes nothing. So a resumed turn either finds a real grant or
136
- * throws `Required` again and parks. eve's own settlement makes that terminal
137
- * rather than an endless loop: it settles each parked authorization once, and
138
- * a `Required` thrown after a completed authorization ends the tool call.
160
+ * Resuming without a completed authorization cannot yield a credential: only
161
+ * `completeAuthorization` writes the store, and a denied, mismatched, or failed
162
+ * callback writes nothing, so a resumed turn either finds a real grant or parks
163
+ * again. eve settles each parked authorization once, so that is terminal rather
164
+ * than a loop.
139
165
  *
140
- * THE CLIENT IS REGISTERED PER ATTEMPT unless `clientId` says otherwise, and
141
- * that is not an optimization — it is what makes the flow work at all. eve
142
- * mints a fresh callback URL for every attempt, carrying the attempt id and a
143
- * run token in its path, while RFC 9700 requires the authorization server to
144
- * match `redirect_uri` against the client's registered list by exact string
145
- * comparison. No fixed registration can name a URL that is generated later, so
146
- * a static client and a dynamic callback cannot both hold. Registering the
147
- * client alongside the callback it belongs to resolves it: each attempt gets a
148
- * public, PKCE-bound client whose one redirect URI is the one URL that attempt
149
- * will return to.
166
+ * The client is registered per attempt unless `clientId` is set. eve mints a
167
+ * fresh callback URL for every attempt, while RFC 9700 requires the
168
+ * authorization server to match `redirect_uri` against the client's registered
169
+ * list by exact string comparison, so no fixed registration can name a URL that
170
+ * is generated later. Each attempt therefore gets a public, PKCE-bound client
171
+ * whose one redirect URI is the callback that attempt returns to. Those client
172
+ * records accumulate in the zone; a server that returns
173
+ * `registration_client_uri` and `registration_access_token` allows RFC 7592
174
+ * deletion once a grant settles.
150
175
  *
151
- * Each attempt therefore leaves a client record in the zone. They are public,
152
- * hold no secret, and are bound to a callback URL that is single-use, but they
153
- * do accumulate; a server that returns `registration_client_uri` and
154
- * `registration_access_token` allows RFC 7592 deletion once a grant settles.
176
+ * Grants are keyed by principal, never by `connectionName`, so two connections
177
+ * never share a token through a shared name and `evict` on one cannot clear the
178
+ * other's grant. A grant obtained with `additionalResources` serves every
179
+ * connection whose resource it covers, so listing the agent's resources on one
180
+ * connection yields one sign-in.
155
181
  *
156
- * Discovery is memoized per definition, so the first authorization pays the
157
- * metadata round trip and later ones do not. Registration is not memoized —
158
- * the redirect URI it binds is different every time.
182
+ * Discovery is memoized per definition. Registration is not, because the
183
+ * redirect URI it binds is different every time.
159
184
  */
160
185
  export declare function interactive(options: KeycardInteractiveOptions): InteractiveAuthorizationDefinition<KeycardResumeState>;
161
- /** A process-local store that drops entries at their advisory expiry. */
162
- export declare function memoryAuthorizedTokenStore(): AuthorizedTokenStore;
186
+ /** A process-local store that drops grants once they can no longer mint a token. */
187
+ export declare function memoryAuthorizedTokenStore(): GrantStore;
163
188
  //# sourceMappingURL=interactive.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"interactive.d.ts","sourceRoot":"","sources":["../../src/interactive.ts"],"names":[],"mappings":"AAAA,OAAO,EAQL,KAAK,qBAAqB,EAC1B,KAAK,yBAAyB,EAC9B,KAAK,4BAA4B,EAEjC,KAAK,aAAa,EACnB,MAAM,kBAAkB,CAAC;AAC1B,OAAO,KAAK,EAEV,kCAAkC,EAClC,SAAS,EAEV,MAAM,iBAAiB,CAAC;AAUzB;;;;;;;;;;;GAWG;AACH,MAAM,WAAW,kBAAkB;IACjC,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,YAAY,EAAE,MAAM,CAAC;IAC9B,QAAQ,CAAC,SAAS,EAAE,SAAS,MAAM,EAAE,CAAC;IACtC,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAC;IAC7B,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAC1B,QAAQ,EAAE,GAAG,EAAE,MAAM,GAAG,SAAS,CAAC;CACnC;AAED,+EAA+E;AAC/E,MAAM,WAAW,eAAe;IAC9B,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,SAAS,CAAC,EAAE,MAAM,CAAC;IAC5B,QAAQ,CAAC,eAAe,CAAC,EAAE,MAAM,CAAC;CACnC;AAED;;;;;;;;GAQG;AACH,MAAM,WAAW,oBAAoB;IACnC,GAAG,CAAC,GAAG,EAAE,MAAM,GAAG,eAAe,GAAG,SAAS,CAAC;IAC9C,GAAG,CAAC,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,eAAe,GAAG,IAAI,CAAC;IAC/C,MAAM,CAAC,GAAG,EAAE,MAAM,GAAG,IAAI,CAAC;CAC3B;AAED,qEAAqE;AACrE,MAAM,WAAW,4BAA4B;IAC3C,2EAA2E;IAC3E,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAC;IAC7B,iDAAiD;IACjD,QAAQ,CAAC,UAAU,CAAC,EAAE,MAAM,CAAC;IAC7B,QAAQ,CAAC,MAAM,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;CACrC;AAED,gEAAgE;AAChE,MAAM,WAAW,gBAAgB;IAC/B,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAC1B;;;;OAIG;IACH,QAAQ,CAAC,YAAY,CAAC,EAAE,MAAM,CAAC;CAChC;AAED,oEAAoE;AACpE,MAAM,WAAW,UAAU;IACzB,KAAK,CAAC,OAAO,EAAE,yBAAyB,GAAG,OAAO,CAAC,qBAAqB,CAAC,CAAC;IAC1E,QAAQ,CAAC,OAAO,EAAE,4BAA4B,GAAG,OAAO,CAAC,aAAa,CAAC,CAAC;IACxE;;;OAGG;IACH,QAAQ,CAAC,CAAC,OAAO,EAAE,4BAA4B,GAAG,OAAO,CAAC,gBAAgB,CAAC,CAAC;CAC7E;AAED,MAAM,WAAW,yBAAyB;IACxC,uDAAuD;IACvD,QAAQ,EAAE,MAAM,CAAC;IACjB,kEAAkE;IAClE,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB;;;;;;;;;;;;;;;;OAgBG;IACH,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,+EAA+E;IAC/E,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB;;;OAGG;IACH,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB;;;OAGG;IACH,kBAAkB,CAAC,EAAE,MAAM,CAAC;IAC5B,qDAAqD;IACrD,aAAa,CAAC,EAAE,MAAM,GAAG,SAAS,MAAM,EAAE,CAAC;IAC3C,uDAAuD;IACvD,mBAAmB,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;IACxC,kEAAkE;IAClE,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,6EAA6E;IAC7E,MAAM,CAAC,EAAE,oBAAoB,CAAC;IAC9B,wEAAwE;IACxE,IAAI,CAAC,EAAE,UAAU,CAAC;CACnB;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA0CG;AACH,wBAAgB,WAAW,CACzB,OAAO,EAAE,yBAAyB,GACjC,kCAAkC,CAAC,kBAAkB,CAAC,CAoKxD;AAED,yEAAyE;AACzE,wBAAgB,0BAA0B,IAAI,oBAAoB,CAmBjE"}
1
+ {"version":3,"file":"interactive.d.ts","sourceRoot":"","sources":["../../src/interactive.ts"],"names":[],"mappings":"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"}
@@ -1,49 +1,57 @@
1
- import { AuthProviderConfigurationError, AuthorizationDeniedError, beginAuthorization, completeAuthorization, fetchAuthorizationServerMetadata, registerClient, StateMismatchError, } from "@keycardai/oauth";
1
+ import { AuthProviderConfigurationError, AuthorizationDeniedError, beginAuthorization, completeAuthorization, fetchAuthorizationServerMetadata, refreshAuthorization, RefreshGrantError, registerClient, StateMismatchError, } from "@keycardai/oauth";
2
2
  import { expiresAt } from "./config.js";
3
3
  import { AuthorizationFailedError, AuthorizationRequiredError, FailureReason, } from "./errors.js";
4
4
  import { principalKey } from "./subjectTokens.js";
5
+ /** A grant is refreshed once it is this close to its advisory expiry. */
6
+ const REFRESH_SKEW_MS = 60_000;
7
+ /** Connection names taken by `interactive()` definitions in this process. */
8
+ const definedConnectionNames = new Set();
9
+ /** Forgets every defined connection name. For tests that define many. */
10
+ export function resetInteractiveDefinitions() {
11
+ definedConnectionNames.clear();
12
+ }
5
13
  /**
6
14
  * Interactive connection auth backed by the zone's web authorization flow.
7
15
  *
8
16
  * The three callbacks eve drives:
9
17
  *
10
- * - `getToken` returns a token only when this package holds one for the
11
- * principal. Otherwise it throws `ConnectionAuthorizationRequiredError`, and
12
- * eve emits `authorization.required`, runs `startAuthorization` in a durable
13
- * step, and parks the turn on its own callback webhook.
14
- * - `startAuthorization` begins the authorization-code flow with PKCE for the
15
- * connection's resources, against eve's minted callback URL, and returns the
16
- * challenge URL plus the `state` and verifier as resume state.
17
- * - `completeAuthorization` redeems the callback against the journaled resume
18
- * state and hands eve the token.
18
+ * - `getToken` returns a token when the store holds a grant for the principal
19
+ * whose resources cover this connection's resource and whose scopes cover
20
+ * `requestScopes`, refreshing it first when it is near expiry and holds a
21
+ * refresh token. Otherwise it throws `ConnectionAuthorizationRequiredError`,
22
+ * and eve emits `authorization.required`, runs `startAuthorization` in a
23
+ * durable step, and parks the turn on its own callback webhook.
24
+ * - `startAuthorization` registers the attempt's client, begins the
25
+ * authorization-code flow with PKCE for the connection's resources against
26
+ * eve's minted callback URL, and returns the challenge URL plus the state,
27
+ * verifier, resources, callback URL and client id as resume state.
28
+ * - `completeAuthorization` redeems the callback as the journaled client and
29
+ * stores the resulting grant.
19
30
  *
20
- * Resuming without a completed authorization cannot yield a credential.
21
- * `getToken` is the only path that returns a token and it reads the store,
22
- * which only `completeAuthorization` writes; a denied, mismatched, or failed
23
- * callback writes nothing. So a resumed turn either finds a real grant or
24
- * throws `Required` again and parks. eve's own settlement makes that terminal
25
- * rather than an endless loop: it settles each parked authorization once, and
26
- * a `Required` thrown after a completed authorization ends the tool call.
31
+ * Resuming without a completed authorization cannot yield a credential: only
32
+ * `completeAuthorization` writes the store, and a denied, mismatched, or failed
33
+ * callback writes nothing, so a resumed turn either finds a real grant or parks
34
+ * again. eve settles each parked authorization once, so that is terminal rather
35
+ * than a loop.
27
36
  *
28
- * THE CLIENT IS REGISTERED PER ATTEMPT unless `clientId` says otherwise, and
29
- * that is not an optimization — it is what makes the flow work at all. eve
30
- * mints a fresh callback URL for every attempt, carrying the attempt id and a
31
- * run token in its path, while RFC 9700 requires the authorization server to
32
- * match `redirect_uri` against the client's registered list by exact string
33
- * comparison. No fixed registration can name a URL that is generated later, so
34
- * a static client and a dynamic callback cannot both hold. Registering the
35
- * client alongside the callback it belongs to resolves it: each attempt gets a
36
- * public, PKCE-bound client whose one redirect URI is the one URL that attempt
37
- * will return to.
37
+ * The client is registered per attempt unless `clientId` is set. eve mints a
38
+ * fresh callback URL for every attempt, while RFC 9700 requires the
39
+ * authorization server to match `redirect_uri` against the client's registered
40
+ * list by exact string comparison, so no fixed registration can name a URL that
41
+ * is generated later. Each attempt therefore gets a public, PKCE-bound client
42
+ * whose one redirect URI is the callback that attempt returns to. Those client
43
+ * records accumulate in the zone; a server that returns
44
+ * `registration_client_uri` and `registration_access_token` allows RFC 7592
45
+ * deletion once a grant settles.
38
46
  *
39
- * Each attempt therefore leaves a client record in the zone. They are public,
40
- * hold no secret, and are bound to a callback URL that is single-use, but they
41
- * do accumulate; a server that returns `registration_client_uri` and
42
- * `registration_access_token` allows RFC 7592 deletion once a grant settles.
47
+ * Grants are keyed by principal, never by `connectionName`, so two connections
48
+ * never share a token through a shared name and `evict` on one cannot clear the
49
+ * other's grant. A grant obtained with `additionalResources` serves every
50
+ * connection whose resource it covers, so listing the agent's resources on one
51
+ * connection yields one sign-in.
43
52
  *
44
- * Discovery is memoized per definition, so the first authorization pays the
45
- * metadata round trip and later ones do not. Registration is not memoized —
46
- * the redirect URI it binds is different every time.
53
+ * Discovery is memoized per definition. Registration is not, because the
54
+ * redirect URI it binds is different every time.
47
55
  */
48
56
  export function interactive(options) {
49
57
  if (!options.resource || !options.resource.trim()) {
@@ -53,6 +61,10 @@ export function interactive(options) {
53
61
  throw new AuthProviderConfigurationError("interactive requires zoneUrl, or an injected flow");
54
62
  }
55
63
  const connectionName = options.connectionName ?? options.resource;
64
+ if (definedConnectionNames.has(connectionName)) {
65
+ throw new AuthProviderConfigurationError(`interactive connectionName "${connectionName}" is already defined in this process. ` +
66
+ "The name is display text, not a token key, so give each connection its own.");
67
+ }
56
68
  const tokens = options.tokens ?? memoryAuthorizedTokenStore();
57
69
  const flow = options.flow ??
58
70
  zoneWebAppFlow(options.zoneUrl, {
@@ -68,6 +80,9 @@ export function interactive(options) {
68
80
  throw new AuthProviderConfigurationError("interactive was given no clientId, so it registers a client per attempt, but the " +
69
81
  "injected flow has no register()");
70
82
  }
83
+ definedConnectionNames.add(connectionName);
84
+ const covers = (grant) => grant.resources.includes(options.resource) &&
85
+ scopes.every((scope) => grant.scopes.includes(scope));
71
86
  /**
72
87
  * The client this attempt runs as: the configured one, or a fresh public
73
88
  * client whose single redirect URI is this attempt's callback.
@@ -104,26 +119,94 @@ export function interactive(options) {
104
119
  }
105
120
  return registered.clientId;
106
121
  };
122
+ /** A per-attempt client is public; only the static client can hold a secret. */
123
+ const secretFor = (clientId) => staticClientId && clientId === staticClientId && options.clientSecret
124
+ ? { clientSecret: options.clientSecret }
125
+ : {};
126
+ /**
127
+ * Refreshes a near-expiry grant as the client it was issued to. A refused
128
+ * refresh drops the grant so the caller parks for a fresh sign-in.
129
+ */
130
+ const refreshGrant = async (principal, grant) => {
131
+ let response;
132
+ try {
133
+ response = await flow.refresh({
134
+ refreshToken: grant.refreshToken,
135
+ clientId: grant.clientId,
136
+ resources: grant.resources,
137
+ ...(grant.scopes.length > 0 ? { scopes: grant.scopes } : {}),
138
+ ...secretFor(grant.clientId),
139
+ });
140
+ }
141
+ catch (cause) {
142
+ if (cause instanceof RefreshGrantError &&
143
+ cause.errorCode === "invalid_grant") {
144
+ // A concurrent step may have rotated this grant first, in which case
145
+ // the refresh token we sent is the stale one and the stored grant is
146
+ // the good one.
147
+ const current = (await tokens.list(principal)).find((candidate) => candidate.id === grant.id);
148
+ if (current && current.refreshToken !== grant.refreshToken) {
149
+ return current;
150
+ }
151
+ await tokens.remove(principal, grant.id);
152
+ throw new AuthorizationRequiredError(connectionName, {
153
+ message: `Connection "${connectionName}" requires authorization: the zone refused to ` +
154
+ `refresh the grant (${cause.message}).`,
155
+ });
156
+ }
157
+ throw new AuthorizationFailedError(connectionName, {
158
+ message: cause instanceof Error
159
+ ? `Refreshing the grant failed: ${cause.message}`
160
+ : "Refreshing the grant failed",
161
+ reason: FailureReason.ACQUISITION_FAILED,
162
+ retryable: cause instanceof RefreshGrantError ? cause.retryable : true,
163
+ });
164
+ }
165
+ const rotated = grantFromResponse(response, {
166
+ id: grant.id,
167
+ clientId: grant.clientId,
168
+ resources: grant.resources,
169
+ scopes: grant.scopes,
170
+ // A server that rotates nothing leaves the old refresh token valid.
171
+ refreshToken: grant.refreshToken,
172
+ });
173
+ await tokens.put(principal, rotated);
174
+ return rotated;
175
+ };
107
176
  return {
108
177
  principalType: "user",
109
178
  /**
110
- * NO definition-level `displayName`. eve validates an authored connection's
111
- * `auth` against a closed key list (`completeAuthorization`, `evict`,
112
- * `getToken`, `principalType`, `startAuthorization`, `vercelConnect`) that
113
- * omits it, so setting it here fails the BUILD with
114
- * `The "auth" field Unknown key "displayName"` for every interactive
115
- * connection. The name still reaches the sign-in prompt: it rides on the
116
- * challenge below, and eve's `stampChallengeDisplayName` resolves
117
- * `definition.displayName ?? challenge.displayName`. The definition-level
118
- * field was only ever a precedence override of a value already carried.
179
+ * No definition-level `displayName`: eve validates an authored connection's
180
+ * `auth` against a closed key list (`completeAuthorization`,
181
+ * `credentialOwner`, `evict`, `getToken`, `principalType`,
182
+ * `startAuthorization`, `vercelConnect`) that omits it. The name rides on the challenge instead, where eve's
183
+ * `stampChallengeDisplayName` falls back to it.
119
184
  */
120
185
  async getToken({ principal }) {
121
- const key = storeKey(principal, connectionName);
122
- const held = tokens.get(key);
123
- if (!held) {
186
+ const key = storeKey(principal);
187
+ const now = Date.now();
188
+ const held = (await tokens.list(key)).filter(covers);
189
+ // A grant is usable while its access token is live or while it holds a
190
+ // refresh token that can mint a new one; an expired grant with no refresh
191
+ // token is dead.
192
+ const usable = held.filter((candidate) => !dead(candidate, now));
193
+ let grant = usable.find((candidate) => !expired(candidate, now)) ?? usable[0];
194
+ if (!grant) {
195
+ await Promise.all(held.map((stale) => tokens.remove(key, stale.id)));
196
+ throw new AuthorizationRequiredError(connectionName);
197
+ }
198
+ if (nearExpiry(grant, now) && grant.refreshToken && flow.refresh) {
199
+ grant = await refreshGrant(key, {
200
+ ...grant,
201
+ refreshToken: grant.refreshToken,
202
+ });
203
+ }
204
+ else if (expired(grant, now)) {
205
+ // Expired, and this flow cannot refresh it.
206
+ await tokens.remove(key, grant.id);
124
207
  throw new AuthorizationRequiredError(connectionName);
125
208
  }
126
- return toTokenResult(held);
209
+ return toTokenResult(grant);
127
210
  },
128
211
  async startAuthorization({ principal, callbackUrl }) {
129
212
  requireUser(principal, connectionName);
@@ -155,21 +238,18 @@ export function interactive(options) {
155
238
  retryable: false,
156
239
  });
157
240
  }
241
+ // The attempt's own client, falling back to the configured one for a
242
+ // resume journaled before clientId existed.
243
+ const clientId = resume.clientId || staticClientId;
158
244
  let response;
159
245
  try {
160
246
  response = await flow.complete({
161
247
  callbackParams: { ...callback.params },
162
248
  state: resume.state,
163
249
  codeVerifier: resume.codeVerifier,
164
- // The attempt's own client. Falls back to the configured one for a
165
- // resume journaled before this field existed.
166
- clientId: resume.clientId || staticClientId,
250
+ clientId,
167
251
  redirectUri: resume.callbackUrl || callbackUrl,
168
- // Only a static client can be confidential; a per-attempt client is
169
- // always public, so there is no secret to send.
170
- ...(staticClientId && options.clientSecret
171
- ? { clientSecret: options.clientSecret }
172
- : {}),
252
+ ...secretFor(clientId),
173
253
  });
174
254
  }
175
255
  catch (cause) {
@@ -183,42 +263,54 @@ export function interactive(options) {
183
263
  retryable: false,
184
264
  });
185
265
  }
186
- const expiry = expiresAt(response.expiresIn);
187
- const token = {
188
- token: response.accessToken,
189
- ...(expiry !== undefined ? { expiresAt: expiry } : {}),
190
- };
191
- tokens.set(storeKey(principal, connectionName), token);
192
- return toTokenResult(token);
266
+ const grant = grantFromResponse(response, {
267
+ id: crypto.randomUUID(),
268
+ clientId,
269
+ resources: resume.resources.length > 0 ? resume.resources : resources,
270
+ scopes,
271
+ });
272
+ await tokens.put(storeKey(principal), grant);
273
+ return toTokenResult(grant);
193
274
  },
194
275
  /**
195
- * eve calls this after a rejected bearer, so the next `getToken` parks the
196
- * turn for a fresh grant instead of handing back the same dead token.
276
+ * eve calls this after a rejected bearer. Every grant covering this
277
+ * connection's resource goes, so the next `getToken` parks for a fresh one;
278
+ * grants for other resources stay.
197
279
  */
198
- evict({ principal }) {
199
- tokens.delete(storeKey(principal, connectionName));
280
+ async evict({ principal }) {
281
+ const key = storeKey(principal);
282
+ const held = await tokens.list(key);
283
+ await Promise.all(held
284
+ .filter((grant) => grant.resources.includes(options.resource))
285
+ .map((grant) => tokens.remove(key, grant.id)));
200
286
  },
201
287
  };
202
288
  }
203
- /** A process-local store that drops entries at their advisory expiry. */
289
+ /** A process-local store that drops grants once they can no longer mint a token. */
204
290
  export function memoryAuthorizedTokenStore() {
205
- const tokens = new Map();
291
+ const grants = new Map();
206
292
  return {
207
- get(key) {
208
- const held = tokens.get(key);
293
+ async list(principal) {
294
+ const held = grants.get(principal);
209
295
  if (!held)
210
- return undefined;
211
- if (held.expiresAt !== undefined && held.expiresAt <= Date.now()) {
212
- tokens.delete(key);
213
- return undefined;
296
+ return [];
297
+ const now = Date.now();
298
+ for (const [id, grant] of held) {
299
+ if (dead(grant, now))
300
+ held.delete(id);
214
301
  }
215
- return held;
302
+ return [...held.values()];
216
303
  },
217
- set(key, token) {
218
- tokens.set(key, token);
304
+ async put(principal, grant) {
305
+ let held = grants.get(principal);
306
+ if (!held) {
307
+ held = new Map();
308
+ grants.set(principal, held);
309
+ }
310
+ held.set(grant.id, grant);
219
311
  },
220
- delete(key) {
221
- tokens.delete(key);
312
+ async remove(principal, grantId) {
313
+ grants.get(principal)?.delete(grantId);
222
314
  },
223
315
  };
224
316
  }
@@ -232,20 +324,29 @@ function zoneWebAppFlow(issuer, options = {}) {
232
324
  };
233
325
  return {
234
326
  async begin(beginOptions) {
235
- return beginAuthorization(issuer, { ...beginOptions, metadata: await discover() });
327
+ return beginAuthorization(issuer, {
328
+ ...beginOptions,
329
+ metadata: await discover(),
330
+ });
236
331
  },
237
332
  async complete(completeOptions) {
238
- return completeAuthorization(issuer, { ...completeOptions, metadata: await discover() });
333
+ return completeAuthorization(issuer, {
334
+ ...completeOptions,
335
+ metadata: await discover(),
336
+ });
337
+ },
338
+ async refresh(refreshOptions) {
339
+ return refreshAuthorization(issuer, {
340
+ ...refreshOptions,
341
+ metadata: await discover(),
342
+ });
239
343
  },
240
344
  /**
241
345
  * One public, PKCE-bound client per authorization, holding the single
242
- * redirect URI that attempt will actually come back to.
243
- *
244
- * `token_endpoint_auth_method: "none"` is what keeps the resume state free
245
- * of credentials: a public client has no secret to journal, and the code is
246
- * bound to the PKCE verifier instead. `refresh_token` is requested so a
247
- * long-lived grant can be renewed without sending the user back through the
248
- * browser.
346
+ * redirect URI that attempt will come back to. `token_endpoint_auth_method:
347
+ * "none"` keeps the resume state free of credentials, and `refresh_token`
348
+ * is requested so a long-lived grant can be renewed without sending the
349
+ * user back through the browser.
249
350
  */
250
351
  async register({ redirectUri, clientName, scopes }) {
251
352
  const registered = await registerClient(issuer, {
@@ -267,18 +368,43 @@ function zoneWebAppFlow(issuer, options = {}) {
267
368
  },
268
369
  };
269
370
  }
270
- function storeKey(principal, connectionName) {
371
+ /**
372
+ * The grant a token response settles. The server's `scope` is authoritative
373
+ * when present; otherwise the scopes are the ones requested (RFC 6749 section
374
+ * 5.1 lets the server omit `scope` when it granted exactly those).
375
+ */
376
+ function grantFromResponse(response, issued) {
377
+ const expiry = expiresAt(response.expiresIn);
378
+ const refreshToken = response.refreshToken ?? issued.refreshToken;
379
+ return {
380
+ id: issued.id,
381
+ accessToken: response.accessToken,
382
+ ...(expiry !== undefined ? { expiresAt: expiry } : {}),
383
+ ...(refreshToken !== undefined ? { refreshToken } : {}),
384
+ clientId: issued.clientId,
385
+ resources: [...issued.resources],
386
+ scopes: response.scope ? splitScopes(response.scope) : [...issued.scopes],
387
+ };
388
+ }
389
+ function expired(grant, now) {
390
+ return grant.expiresAt !== undefined && grant.expiresAt <= now;
391
+ }
392
+ /** Expired with no refresh token: nothing can mint a new access token. */
393
+ function dead(grant, now) {
394
+ return expired(grant, now) && !grant.refreshToken;
395
+ }
396
+ function nearExpiry(grant, now) {
397
+ return (grant.expiresAt !== undefined && grant.expiresAt - REFRESH_SKEW_MS <= now);
398
+ }
399
+ function storeKey(principal) {
271
400
  if (principal.type !== "user")
272
- return `${connectionName}|app`;
273
- return `${connectionName}|${principalKey(principal)}`;
401
+ return "app";
402
+ return principalKey(principal);
274
403
  }
275
- function toTokenResult(token) {
404
+ function toTokenResult(grant) {
276
405
  return {
277
- token: token.token,
278
- ...(token.expiresAt !== undefined ? { expiresAt: token.expiresAt } : {}),
279
- ...(token.providerSubject !== undefined
280
- ? { providerSubject: token.providerSubject }
281
- : {}),
406
+ token: grant.accessToken,
407
+ ...(grant.expiresAt !== undefined ? { expiresAt: grant.expiresAt } : {}),
282
408
  };
283
409
  }
284
410
  function requireUser(principal, connectionName) {
@@ -294,6 +420,8 @@ function requireUser(principal, connectionName) {
294
420
  function splitScopes(scopes) {
295
421
  if (scopes === undefined)
296
422
  return [];
297
- return Array.isArray(scopes) ? [...scopes] : scopes.split(" ").filter(Boolean);
423
+ return Array.isArray(scopes)
424
+ ? [...scopes]
425
+ : scopes.split(" ").filter(Boolean);
298
426
  }
299
427
  //# sourceMappingURL=interactive.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"interactive.js","sourceRoot":"","sources":["../../src/interactive.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"interactive.js","sourceRoot":"","sources":["../../src/interactive.ts"],"names":[],"mappings":"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"}
@@ -7,4 +7,5 @@
7
7
  */
8
8
  export { appPrincipal, bearerRequest, connectionContext, expiredJwt, fakeVerifier, fakeZoneClient, sessionAuthContext, unsignedJwt, userPrincipal, validJwt, } from "./testUtils.js";
9
9
  export type { FakeZoneClient, FakeZoneClientOptions, ZoneCalls } from "./testUtils.js";
10
+ export { resetInteractiveDefinitions } from "../interactive.js";
10
11
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/testing/index.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AACH,OAAO,EACL,YAAY,EACZ,aAAa,EACb,iBAAiB,EACjB,UAAU,EACV,YAAY,EACZ,cAAc,EACd,kBAAkB,EAClB,WAAW,EACX,aAAa,EACb,QAAQ,GACT,MAAM,gBAAgB,CAAC;AACxB,YAAY,EAAE,cAAc,EAAE,qBAAqB,EAAE,SAAS,EAAE,MAAM,gBAAgB,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/testing/index.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AACH,OAAO,EACL,YAAY,EACZ,aAAa,EACb,iBAAiB,EACjB,UAAU,EACV,YAAY,EACZ,cAAc,EACd,kBAAkB,EAClB,WAAW,EACX,aAAa,EACb,QAAQ,GACT,MAAM,gBAAgB,CAAC;AACxB,YAAY,EAAE,cAAc,EAAE,qBAAqB,EAAE,SAAS,EAAE,MAAM,gBAAgB,CAAC;AACvF,OAAO,EAAE,2BAA2B,EAAE,MAAM,mBAAmB,CAAC"}
@@ -6,4 +6,5 @@
6
6
  * `@keycardai/eve/testing`.
7
7
  */
8
8
  export { appPrincipal, bearerRequest, connectionContext, expiredJwt, fakeVerifier, fakeZoneClient, sessionAuthContext, unsignedJwt, userPrincipal, validJwt, } from "./testUtils.js";
9
+ export { resetInteractiveDefinitions } from "../interactive.js";
9
10
  //# sourceMappingURL=index.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/testing/index.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AACH,OAAO,EACL,YAAY,EACZ,aAAa,EACb,iBAAiB,EACjB,UAAU,EACV,YAAY,EACZ,cAAc,EACd,kBAAkB,EAClB,WAAW,EACX,aAAa,EACb,QAAQ,GACT,MAAM,gBAAgB,CAAC"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/testing/index.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AACH,OAAO,EACL,YAAY,EACZ,aAAa,EACb,iBAAiB,EACjB,UAAU,EACV,YAAY,EACZ,cAAc,EACd,kBAAkB,EAClB,WAAW,EACX,aAAa,EACb,QAAQ,GACT,MAAM,gBAAgB,CAAC;AAExB,OAAO,EAAE,2BAA2B,EAAE,MAAM,mBAAmB,CAAC"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@keycardai/eve",
3
- "version": "0.2.0",
3
+ "version": "0.4.0",
4
4
  "description": "[Preview] Keycard auth adapters for eve agents: a zone token verifier for the channel auth walk, Keycard-backed connection auth, and interactive authorization over the zone's web flow",
5
5
  "license": "MIT",
6
6
  "repository": {
@@ -30,15 +30,15 @@
30
30
  }
31
31
  },
32
32
  "dependencies": {
33
- "@keycardai/oauth": "0.24.1"
33
+ "@keycardai/oauth": "0.25.0"
34
34
  },
35
35
  "peerDependencies": {
36
- "eve": ">=0.54.3 <0.55.0"
36
+ "eve": ">=0.71.3 <0.72.0"
37
37
  },
38
38
  "devDependencies": {
39
39
  "@jest/globals": "^30.0.4",
40
40
  "@types/node": "^25.6.0",
41
- "eve": "0.54.3",
41
+ "eve": "0.71.3",
42
42
  "jest": "^30.0.4",
43
43
  "ts-jest": "^29.4.7",
44
44
  "typescript": "^5.8.3"