@keycardai/eve 0.1.0 → 0.3.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 +121 -13
- package/dist/esm/connections.d.ts +12 -0
- package/dist/esm/connections.d.ts.map +1 -1
- package/dist/esm/connections.js +0 -3
- package/dist/esm/connections.js.map +1 -1
- package/dist/esm/index.d.ts +1 -1
- package/dist/esm/index.d.ts.map +1 -1
- package/dist/esm/index.js.map +1 -1
- package/dist/esm/interactive.d.ts +142 -44
- package/dist/esm/interactive.d.ts.map +1 -1
- package/dist/esm/interactive.js +306 -69
- package/dist/esm/interactive.js.map +1 -1
- package/dist/esm/requireAuth.d.ts +9 -6
- package/dist/esm/requireAuth.d.ts.map +1 -1
- package/dist/esm/requireAuth.js +1 -4
- package/dist/esm/requireAuth.js.map +1 -1
- package/dist/esm/testing/index.d.ts +1 -0
- package/dist/esm/testing/index.d.ts.map +1 -1
- package/dist/esm/testing/index.js +1 -0
- package/dist/esm/testing/index.js.map +1 -1
- package/package.json +4 -4
package/README.md
CHANGED
|
@@ -16,12 +16,19 @@ 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.
|
|
20
|
-
built and verified against eve `0.
|
|
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
|
|
21
21
|
releases most days, and its connection and auth surfaces are still moving, so
|
|
22
22
|
the range deliberately stops at the next minor rather than tracking `^`. Widen
|
|
23
23
|
it only after re-running this package's tests against the newer eve.
|
|
24
24
|
|
|
25
|
+
The narrowness is the point rather than an oversight, and so is keeping the
|
|
26
|
+
range current: a consumer who runs a newer eve and installs this anyway —
|
|
27
|
+
`--legacy-peer-deps` — silently loses the check, and the incompatibilities
|
|
28
|
+
surface at build time instead. Two of them are what the 0.47 → 0.54 bump had to
|
|
29
|
+
fix: an `auth` key list that `displayName` is not in, and a `requireAuth`
|
|
30
|
+
options type with no `reason` field.
|
|
31
|
+
|
|
25
32
|
eve itself declares `engines.node: ">=24"` and is ESM only. This package
|
|
26
33
|
imports eve for types only (`import type { ... } from "eve/connections"`), so
|
|
27
34
|
nothing here pulls eve into the runtime and the package builds and tests on
|
|
@@ -139,25 +146,56 @@ export default defineMcpClientConnection({
|
|
|
139
146
|
description: "Documents the user has authorized.",
|
|
140
147
|
auth: Keycard.interactive({
|
|
141
148
|
zoneUrl: process.env.KEYCARD_ZONE_URL!,
|
|
142
|
-
clientId: process.env.KEYCARD_CLIENT_ID!,
|
|
143
149
|
resource: "https://docs.example.com",
|
|
144
150
|
requestScopes: ["documents.read"],
|
|
151
|
+
connectionName: "Docs",
|
|
145
152
|
}),
|
|
146
153
|
});
|
|
147
154
|
```
|
|
148
155
|
|
|
156
|
+
**There is no `clientId`, and adding one usually breaks the flow.** eve mints a
|
|
157
|
+
fresh callback URL for every attempt
|
|
158
|
+
(`/eve/v1/connections/:name/callback/:attemptId/:token`) while
|
|
159
|
+
[RFC 9700][rfc9700] requires the authorization server to match `redirect_uri`
|
|
160
|
+
against the client's registered list by exact string comparison. A client
|
|
161
|
+
registered ahead of time cannot name a URL that is generated later, so the
|
|
162
|
+
request is rejected with something like `Unauthorized redirect URI`. Leaving
|
|
163
|
+
`clientId` unset registers a client per attempt instead (RFC 7591), whose
|
|
164
|
+
single redirect URI is the callback that attempt will return to. Each client is
|
|
165
|
+
public and PKCE-bound, so nothing secret enters eve's durable resume state; if
|
|
166
|
+
the server issues a confidential client anyway, the attempt is abandoned rather
|
|
167
|
+
than journaling a secret.
|
|
168
|
+
|
|
169
|
+
Set `clientId` only when that client's registered redirect URIs already cover
|
|
170
|
+
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 `urn:app:my-agent`
|
|
173
|
+
fails with `Unsupported client identifier prefix: urn`.
|
|
174
|
+
|
|
175
|
+
Per-attempt clients accumulate in the zone. They hold no secret and their
|
|
176
|
+
callback is single-use, but a server returning `registration_client_uri` and
|
|
177
|
+
`registration_access_token` allows RFC 7592 deletion once a grant settles.
|
|
178
|
+
|
|
179
|
+
[rfc9700]: https://datatracker.ietf.org/doc/html/rfc9700
|
|
180
|
+
[cimd]: https://datatracker.ietf.org/doc/html/draft-ietf-oauth-client-id-metadata-document-02
|
|
181
|
+
|
|
149
182
|
The definition implements the same three-method form as eve's
|
|
150
183
|
`defineInteractiveAuthorization`, over `@keycardai/oauth`'s v3 web-app flow:
|
|
151
184
|
|
|
152
|
-
- `getToken`
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
the
|
|
185
|
+
- `getToken` looks up the principal's stored grants and returns the access
|
|
186
|
+
token of one whose resources cover this connection's `resource` and whose
|
|
187
|
+
scopes cover `requestScopes`. Within 60 seconds of expiry, a grant holding a
|
|
188
|
+
refresh token is refreshed first (see below). With no usable grant it throws
|
|
189
|
+
`ConnectionAuthorizationRequiredError`, so eve emits
|
|
190
|
+
`authorization.required`, runs `startAuthorization` in a durable step, and
|
|
191
|
+
parks the turn on a framework-owned callback.
|
|
192
|
+
- `startAuthorization` registers this attempt's client (unless `clientId` is
|
|
193
|
+
set), calls `beginAuthorization` for the connection's resource list against
|
|
194
|
+
eve's minted callback URL, and returns the challenge URL plus the `state`,
|
|
195
|
+
PKCE verifier and client id as JSON resume state.
|
|
159
196
|
- `completeAuthorization` calls `completeAuthorization` with eve's callback
|
|
160
|
-
params and the journaled resume state,
|
|
197
|
+
params and the journaled resume state, redeeming as the client that attempt's
|
|
198
|
+
authorization request ran as, and stores the resulting grant.
|
|
161
199
|
|
|
162
200
|
**Resume without authorization cannot yield a credential.** `getToken` is the
|
|
163
201
|
only path that returns a token, and it reads a store only
|
|
@@ -169,6 +207,72 @@ an authorization has settled ends the tool call. User denial is reported as
|
|
|
169
207
|
`ConnectionAuthorizationFailedError` with `reason: "access_denied"` and
|
|
170
208
|
`retryable: false`, so eve stops re-prompting.
|
|
171
209
|
|
|
210
|
+
### Grants: what is stored, and for how long
|
|
211
|
+
|
|
212
|
+
`completeAuthorization` stores a grant, not a bare token: the access token and
|
|
213
|
+
its expiry, the refresh token the zone returned, the client id the grant was
|
|
214
|
+
issued to, and the resources and scopes granted. Grants are keyed by the
|
|
215
|
+
principal, never by `connectionName`, which is display and error text only;
|
|
216
|
+
two `Keycard.interactive()` definitions in one process with the same
|
|
217
|
+
`connectionName` fail at definition time with
|
|
218
|
+
`AuthProviderConfigurationError`. Because a grant is matched on what it covers,
|
|
219
|
+
a connection listing the agent's other resources in `additionalResources`
|
|
220
|
+
yields one sign-in that serves every connection whose resource is in the list.
|
|
221
|
+
|
|
222
|
+
When a grant is within 60 seconds of expiry and holds a refresh token,
|
|
223
|
+
`getToken` posts `grant_type=refresh_token` to the zone as the grant's own
|
|
224
|
+
client (public, no secret; a per-attempt client registers with
|
|
225
|
+
`refresh_token` among its grant types), stores the rotated access and refresh
|
|
226
|
+
token pair, and returns the new access token without parking. A refresh the
|
|
227
|
+
zone refuses with `invalid_grant` deletes the grant and throws `Required`, so
|
|
228
|
+
the turn parks for a fresh sign-in. A transport or 5xx failure keeps the grant
|
|
229
|
+
and fails the tool call with `retryable: true`. A grant without a refresh token
|
|
230
|
+
parks at expiry, as before.
|
|
231
|
+
|
|
232
|
+
`evict` removes every grant of the principal that covers this connection's
|
|
233
|
+
resource, leaving grants for other resources in place.
|
|
234
|
+
|
|
235
|
+
### Plugging a durable grant store
|
|
236
|
+
|
|
237
|
+
The default store is process-local, so a restarted agent parks once more for
|
|
238
|
+
each user. To keep grants across processes, pass `tokens` an object of this
|
|
239
|
+
shape:
|
|
240
|
+
|
|
241
|
+
```ts
|
|
242
|
+
import type { AuthorizedGrant, GrantStore } from "@keycardai/eve";
|
|
243
|
+
|
|
244
|
+
export function redisGrantStore(redis: {
|
|
245
|
+
hgetall(key: string): Promise<Record<string, string>>;
|
|
246
|
+
hset(key: string, field: string, value: string): Promise<unknown>;
|
|
247
|
+
hdel(key: string, field: string): Promise<unknown>;
|
|
248
|
+
}): GrantStore {
|
|
249
|
+
const key = (principal: string) => `keycard:grants:${principal}`;
|
|
250
|
+
return {
|
|
251
|
+
async list(principal) {
|
|
252
|
+
const rows = await redis.hgetall(key(principal));
|
|
253
|
+
return Object.values(rows).map((row) => JSON.parse(row) as AuthorizedGrant);
|
|
254
|
+
},
|
|
255
|
+
async put(principal, grant) {
|
|
256
|
+
await redis.hset(key(principal), grant.id, JSON.stringify(grant));
|
|
257
|
+
},
|
|
258
|
+
async remove(principal, grantId) {
|
|
259
|
+
await redis.hdel(key(principal), grantId);
|
|
260
|
+
},
|
|
261
|
+
};
|
|
262
|
+
}
|
|
263
|
+
```
|
|
264
|
+
|
|
265
|
+
Every method is async, and `put` with an `id` already held replaces that grant
|
|
266
|
+
(a refresh rewrites the rotated pair under the same `id`). The same three
|
|
267
|
+
methods map onto Vercel KV's `hgetall`, `hset` and `hdel`, or any other
|
|
268
|
+
key-value backend.
|
|
269
|
+
|
|
270
|
+
Choosing a durable store puts refresh tokens at rest in that backend. Each one
|
|
271
|
+
is a long-lived credential for the user's resources, so the backend's access
|
|
272
|
+
control and encryption are yours to provide. This package never writes a grant
|
|
273
|
+
into eve's session attributes for that reason: a refresh token must not enter
|
|
274
|
+
eve's durable state.
|
|
275
|
+
|
|
172
276
|
## Parity with `@keycardai/langchain`
|
|
173
277
|
|
|
174
278
|
The two packages implement the same Keycard access model against different
|
|
@@ -212,8 +316,12 @@ const auth = Keycard.onBehalfOf({
|
|
|
212
316
|
`fakeZoneClient()` records every exchange, impersonation, and client
|
|
213
317
|
credentials call, and can fail one resource or every request. `keycardAuth()`
|
|
214
318
|
takes a `verify` seam in place of the JWKS-backed verifier, and
|
|
215
|
-
`Keycard.interactive()` takes a `flow` seam in place of the
|
|
216
|
-
|
|
319
|
+
`Keycard.interactive()` takes a `flow` seam in place of the web-flow calls:
|
|
320
|
+
`begin`, `complete`, `register` for per-attempt clients, and `refresh`. A flow
|
|
321
|
+
without `register` is rejected at construction unless a `clientId` is also
|
|
322
|
+
given, so a test cannot accidentally exercise a combination that cannot work in
|
|
323
|
+
production. An injected `client` or `flow` supersedes `zoneUrl`, so a test needs
|
|
324
|
+
no zone.
|
|
217
325
|
|
|
218
326
|
## Not included: the Keycard gateway MCP proxy
|
|
219
327
|
|
|
@@ -1,5 +1,17 @@
|
|
|
1
1
|
import type { ConnectionPrincipal, NonInteractiveAuthorizationDefinition } from "eve/connections";
|
|
2
2
|
import { type KeycardConnectionOptions } from "./config.js";
|
|
3
|
+
/**
|
|
4
|
+
* None of these definitions carry a `displayName`. eve validates an authored
|
|
5
|
+
* connection's `auth` against a closed key list (`completeAuthorization`,
|
|
6
|
+
* `evict`, `getToken`, `principalType`, `startAuthorization`, `vercelConnect`),
|
|
7
|
+
* and a definition carrying any other key fails the build with
|
|
8
|
+
* `The "auth" field Unknown key "displayName"`. The only consumer of the field
|
|
9
|
+
* is eve's `stampChallengeDisplayName`, which resolves
|
|
10
|
+
* `definition.displayName ?? challenge.displayName`, so an interactive
|
|
11
|
+
* definition names itself on the challenge instead (see {@link interactive}),
|
|
12
|
+
* a non-interactive one has no challenge to name, and tools name a provider
|
|
13
|
+
* through `ToolAuthOptions.displayName` at the call site.
|
|
14
|
+
*/
|
|
3
15
|
/** Options for {@link impersonate}. */
|
|
4
16
|
export interface KeycardImpersonateOptions extends KeycardConnectionOptions {
|
|
5
17
|
/**
|
|
@@ -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,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,
|
|
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;;;;;;;;;;;GAWG;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"}
|
package/dist/esm/connections.js
CHANGED
|
@@ -14,7 +14,6 @@ export function asSelf(options) {
|
|
|
14
14
|
const config = resolveConnectionConfig(options, "asSelf");
|
|
15
15
|
return {
|
|
16
16
|
principalType: "app",
|
|
17
|
-
displayName: config.connectionName,
|
|
18
17
|
async getToken() {
|
|
19
18
|
const request = {
|
|
20
19
|
resource: config.resource,
|
|
@@ -44,7 +43,6 @@ export function onBehalfOf(options) {
|
|
|
44
43
|
const config = resolveConnectionConfig(options, "onBehalfOf");
|
|
45
44
|
return {
|
|
46
45
|
principalType: "user",
|
|
47
|
-
displayName: config.connectionName,
|
|
48
46
|
async getToken({ principal }) {
|
|
49
47
|
requireUser(principal, config.connectionName);
|
|
50
48
|
const subjectToken = readSubjectToken(principal, config.subjectTokens);
|
|
@@ -103,7 +101,6 @@ export function impersonate(options) {
|
|
|
103
101
|
}
|
|
104
102
|
return {
|
|
105
103
|
principalType: typeof identifier === "function" ? "user" : "app",
|
|
106
|
-
displayName: config.connectionName,
|
|
107
104
|
async getToken({ principal }) {
|
|
108
105
|
let userIdentifier;
|
|
109
106
|
if (typeof identifier === "function") {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"connections.js","sourceRoot":"","sources":["../../src/connections.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,8BAA8B,EAC9B,SAAS,GAIV,MAAM,kBAAkB,CAAC;AAO1B,OAAO,EAAE,SAAS,EAAE,uBAAuB,EAAiC,MAAM,aAAa,CAAC;AAChG,OAAO,EAAE,wBAAwB,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AACtE,OAAO,EAAE,mBAAmB,EAAE,MAAM,aAAa,CAAC;AAClD,OAAO,EAAE,YAAY,EAAE,gBAAgB,EAAE,MAAM,oBAAoB,CAAC;
|
|
1
|
+
{"version":3,"file":"connections.js","sourceRoot":"","sources":["../../src/connections.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,8BAA8B,EAC9B,SAAS,GAIV,MAAM,kBAAkB,CAAC;AAO1B,OAAO,EAAE,SAAS,EAAE,uBAAuB,EAAiC,MAAM,aAAa,CAAC;AAChG,OAAO,EAAE,wBAAwB,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AACtE,OAAO,EAAE,mBAAmB,EAAE,MAAM,aAAa,CAAC;AAClD,OAAO,EAAE,YAAY,EAAE,gBAAgB,EAAE,MAAM,oBAAoB,CAAC;AAwBpE;;;;;;GAMG;AACH,MAAM,UAAU,MAAM,CACpB,OAAiC;IAEjC,MAAM,MAAM,GAAG,uBAAuB,CAAC,OAAO,EAAE,QAAQ,CAAC,CAAC;IAE1D,OAAO;QACL,aAAa,EAAE,KAAK;QACpB,KAAK,CAAC,QAAQ;YACZ,MAAM,OAAO,GAA6B;gBACxC,QAAQ,EAAE,MAAM,CAAC,QAAQ;gBACzB,GAAG,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,KAAK,EAAE,MAAM,CAAC,KAAK,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;gBAChD,GAAG,CAAC,MAAM,MAAM,CAAC,gBAAgB,EAAE,CAAC;aACrC,CAAC;YACF,OAAO,WAAW,CAChB,MAAM,OAAO,CAAC,MAAM,CAAC,cAAc,EAAE,GAAG,EAAE,CACxC,MAAM,CAAC,UAAU,EAAE,CAAC,sBAAsB,CAAC,OAAO,CAAC,CACpD,CACF,CAAC;QACJ,CAAC;KACF,CAAC;AACJ,CAAC;AAED;;;;;;;;;;;;;;GAcG;AACH,MAAM,UAAU,UAAU,CACxB,OAAiC;IAEjC,MAAM,MAAM,GAAG,uBAAuB,CAAC,OAAO,EAAE,YAAY,CAAC,CAAC;IAE9D,OAAO;QACL,aAAa,EAAE,MAAM;QACrB,KAAK,CAAC,QAAQ,CAAC,EAAE,SAAS,EAAE;YAC1B,WAAW,CAAC,SAAS,EAAE,MAAM,CAAC,cAAc,CAAC,CAAC;YAE9C,MAAM,YAAY,GAAG,gBAAgB,CAAC,SAAS,EAAE,MAAM,CAAC,aAAa,CAAC,CAAC;YACvE,IAAI,CAAC,YAAY,EAAE,CAAC;gBAClB,MAAM,IAAI,wBAAwB,CAAC,MAAM,CAAC,cAAc,EAAE;oBACxD,OAAO,EACL,sEAAsE;wBACtE,wEAAwE;wBACxE,2EAA2E;wBAC3E,cAAc;oBAChB,MAAM,EAAE,aAAa,CAAC,yBAAyB;oBAC/C,SAAS,EAAE,KAAK;iBACjB,CAAC,CAAC;YACL,CAAC;YACD,IAAI,mBAAmB,CAAC,YAAY,CAAC,EAAE,CAAC;gBACtC,MAAM,CAAC,aAAa,CAAC,MAAM,CAAC,YAAY,CAAC,SAAS,CAAC,CAAC,CAAC;gBACrD,MAAM,IAAI,wBAAwB,CAAC,MAAM,CAAC,cAAc,EAAE;oBACxD,OAAO,EACL,iFAAiF;oBACnF,MAAM,EAAE,aAAa,CAAC,qBAAqB;oBAC3C,SAAS,EAAE,KAAK;iBACjB,CAAC,CAAC;YACL,CAAC;YAED,IAAI,OAA6B,CAAC;YAClC,IAAI,MAAM,CAAC,UAAU,EAAE,CAAC;gBACtB,OAAO,GAAG,MAAM,MAAM,CAAC,UAAU,CAAC,2BAA2B,CAC3D,YAAY,EACZ,MAAM,CAAC,QAAQ,CAChB,CAAC;YACJ,CAAC;iBAAM,CAAC;gBACN,OAAO,GAAG;oBACR,YAAY;oBACZ,QAAQ,EAAE,MAAM,CAAC,QAAQ;oBACzB,gBAAgB,EAAE,SAAS,CAAC,YAAY;iBACzC,CAAC;YACJ,CAAC;YACD,IAAI,MAAM,CAAC,KAAK;gBAAE,OAAO,GAAG,EAAE,GAAG,OAAO,EAAE,KAAK,EAAE,MAAM,CAAC,KAAK,EAAE,CAAC;YAEhE,OAAO,WAAW,CAChB,MAAM,OAAO,CAAC,MAAM,CAAC,cAAc,EAAE,GAAG,EAAE,CAAC,MAAM,CAAC,UAAU,EAAE,CAAC,aAAa,CAAC,OAAO,CAAC,CAAC,CACvF,CAAC;QACJ,CAAC;KACF,CAAC;AACJ,CAAC;AAED;;;;;;;;;;;GAWG;AACH,MAAM,UAAU,WAAW,CACzB,OAAkC;IAElC,MAAM,MAAM,GAAG,uBAAuB,CAAC,OAAO,EAAE,aAAa,CAAC,CAAC;IAC/D,MAAM,UAAU,GAAG,OAAO,CAAC,cAAc,CAAC;IAC1C,IAAI,OAAO,UAAU,KAAK,QAAQ,IAAI,CAAC,UAAU,CAAC,IAAI,EAAE,EAAE,CAAC;QACzD,MAAM,IAAI,8BAA8B,CACtC,kDAAkD,CACnD,CAAC;IACJ,CAAC;IAED,OAAO;QACL,aAAa,EAAE,OAAO,UAAU,KAAK,UAAU,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,KAAK;QAChE,KAAK,CAAC,QAAQ,CAAC,EAAE,SAAS,EAAE;YAC1B,IAAI,cAAsB,CAAC;YAC3B,IAAI,OAAO,UAAU,KAAK,UAAU,EAAE,CAAC;gBACrC,WAAW,CAAC,SAAS,EAAE,MAAM,CAAC,cAAc,CAAC,CAAC;gBAC9C,cAAc,GAAG,UAAU,CAAC,SAAS,CAAC,CAAC;YACzC,CAAC;iBAAM,CAAC;gBACN,cAAc,GAAG,UAAU,CAAC;YAC9B,CAAC;YACD,IAAI,CAAC,cAAc,IAAI,CAAC,cAAc,CAAC,IAAI,EAAE,EAAE,CAAC;gBAC9C,MAAM,IAAI,wBAAwB,CAAC,MAAM,CAAC,cAAc,EAAE;oBACxD,OAAO,EAAE,8DAA8D;oBACvE,MAAM,EAAE,aAAa,CAAC,kBAAkB;oBACxC,SAAS,EAAE,KAAK;iBACjB,CAAC,CAAC;YACL,CAAC;YAED,OAAO,WAAW,CAChB,MAAM,OAAO,CAAC,MAAM,CAAC,cAAc,EAAE,GAAG,EAAE,CACxC,MAAM,CAAC,UAAU,EAAE,CAAC,WAAW,CAAC;gBAC9B,cAAc;gBACd,QAAQ,EAAE,MAAM,CAAC,QAAQ;gBACzB,GAAG,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,KAAK,EAAE,MAAM,CAAC,KAAK,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;aACjD,CAAC,CACH,CACF,CAAC;QACJ,CAAC;KACF,CAAC;AACJ,CAAC;AAED;;;;;GAKG;AACH,SAAS,WAAW,CAClB,SAA8B,EAC9B,cAAsB;IAEtB,IAAI,SAAS,CAAC,IAAI,KAAK,MAAM;QAAE,OAAO;IACtC,MAAM,IAAI,wBAAwB,CAAC,cAAc,EAAE;QACjD,OAAO,EACL,6EAA6E;YAC7E,iBAAiB;QACnB,MAAM,EAAE,aAAa,CAAC,kBAAkB;QACxC,SAAS,EAAE,KAAK;KACjB,CAAC,CAAC;AACL,CAAC;AAED,gFAAgF;AAChF,KAAK,UAAU,OAAO,CACpB,cAAsB,EACtB,OAAqC;IAErC,IAAI,CAAC;QACH,OAAO,MAAM,OAAO,EAAE,CAAC;IACzB,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,MAAM,IAAI,wBAAwB,CAAC,cAAc,EAAE;YACjD,OAAO,EAAE,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,0BAA0B;YAC5E,MAAM,EAAE,aAAa,CAAC,kBAAkB;YACxC,SAAS,EAAE,KAAK;SACjB,CAAC,CAAC;IACL,CAAC;AACH,CAAC;AAED,SAAS,WAAW,CAAC,QAAuB;IAC1C,MAAM,MAAM,GAAG,SAAS,CAAC,QAAQ,CAAC,SAAS,CAAC,CAAC;IAC7C,OAAO;QACL,KAAK,EAAE,QAAQ,CAAC,WAAW;QAC3B,GAAG,CAAC,MAAM,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,SAAS,EAAE,MAAM,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;KACvD,CAAC;AACJ,CAAC"}
|
package/dist/esm/index.d.ts
CHANGED
|
@@ -19,7 +19,7 @@ export type { KeycardAuthOptions, SubjectTokenRetention } from "./auth.js";
|
|
|
19
19
|
export { asSelf, impersonate, onBehalfOf } from "./connections.js";
|
|
20
20
|
export type { KeycardImpersonateOptions } from "./connections.js";
|
|
21
21
|
export { interactive, memoryAuthorizedTokenStore } from "./interactive.js";
|
|
22
|
-
export type {
|
|
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";
|
package/dist/esm/index.d.ts.map
CHANGED
|
@@ -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,
|
|
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,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"}
|
package/dist/esm/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AACH,OAAO,EAAE,WAAW,EAAE,MAAM,WAAW,CAAC;AAGxC,OAAO,EAAE,MAAM,EAAE,WAAW,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAC;AAGnE,OAAO,EAAE,WAAW,EAAE,0BAA0B,EAAE,MAAM,kBAAkB,CAAC;
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AACH,OAAO,EAAE,WAAW,EAAE,MAAM,WAAW,CAAC;AAGxC,OAAO,EAAE,MAAM,EAAE,WAAW,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAC;AAGnE,OAAO,EAAE,WAAW,EAAE,0BAA0B,EAAE,MAAM,kBAAkB,CAAC;AAa3E,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;AAG7D,OAAO,EACL,wBAAwB,EACxB,uBAAuB,EACvB,uBAAuB,GACxB,MAAM,oBAAoB,CAAC;AAG5B,OAAO,EAAE,iBAAiB,EAAE,MAAM,iBAAiB,CAAC;AAGpD,OAAO,EAAE,MAAM,EAAE,WAAW,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAC;AACnE,OAAO,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAC;AAE/C;;;GAGG;AACH,MAAM,CAAC,MAAM,OAAO,GAAG,MAAM,CAAC,MAAM,CAAC;IACnC,MAAM;IACN,WAAW;IACX,WAAW;IACX,UAAU;CACX,CAAC,CAAC"}
|
|
@@ -1,90 +1,188 @@
|
|
|
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.
|
|
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}).
|
|
8
11
|
*/
|
|
9
12
|
export interface KeycardResumeState {
|
|
10
13
|
readonly state: string;
|
|
11
14
|
readonly codeVerifier: string;
|
|
12
15
|
readonly resources: readonly string[];
|
|
13
16
|
readonly callbackUrl: string;
|
|
17
|
+
readonly clientId: string;
|
|
14
18
|
readonly [key: string]: JsonValue;
|
|
15
19
|
}
|
|
16
|
-
/**
|
|
17
|
-
|
|
18
|
-
|
|
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;
|
|
19
31
|
readonly expiresAt?: number;
|
|
20
|
-
readonly
|
|
32
|
+
readonly refreshToken?: string;
|
|
33
|
+
readonly clientId: string;
|
|
34
|
+
readonly resources: readonly string[];
|
|
35
|
+
readonly scopes: readonly string[];
|
|
21
36
|
}
|
|
22
37
|
/**
|
|
23
|
-
* Where completed
|
|
38
|
+
* Where completed grants live between turns, keyed by principal.
|
|
24
39
|
*
|
|
25
|
-
* eve caches a resolved bearer for the duration of a step
|
|
26
|
-
* `getToken` after that
|
|
27
|
-
*
|
|
28
|
-
* default is process-local, so a
|
|
29
|
-
*
|
|
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, Vercel KV) 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.
|
|
30
47
|
*/
|
|
31
|
-
export interface
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
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>;
|
|
35
52
|
}
|
|
36
|
-
/**
|
|
53
|
+
/** What one authorization attempt needs its own OAuth client for. */
|
|
54
|
+
export interface RegisterAttemptClientOptions {
|
|
55
|
+
/** eve's callback URL for this attempt. The client's only redirect URI. */
|
|
56
|
+
readonly redirectUri: string;
|
|
57
|
+
/** Name the zone shows on the consent screen. */
|
|
58
|
+
readonly clientName?: string;
|
|
59
|
+
readonly scopes?: readonly string[];
|
|
60
|
+
}
|
|
61
|
+
/** A client the authorization server issued for one attempt. */
|
|
62
|
+
export interface RegisteredClient {
|
|
63
|
+
readonly clientId: string;
|
|
64
|
+
/**
|
|
65
|
+
* Only ever set by a server that ignored the public-client registration
|
|
66
|
+
* request. {@link interactive} refuses such a client rather than journaling
|
|
67
|
+
* a secret into eve's durable state.
|
|
68
|
+
*/
|
|
69
|
+
readonly clientSecret?: string;
|
|
70
|
+
}
|
|
71
|
+
/** The web-flow calls this adapter makes, as one seam for tests. */
|
|
37
72
|
export interface WebAppFlow {
|
|
38
73
|
begin(options: BeginAuthorizationOptions): Promise<AuthorizationRedirect>;
|
|
39
74
|
complete(options: CompleteAuthorizationOptions): Promise<TokenResponse>;
|
|
75
|
+
/**
|
|
76
|
+
* Registers the client for one attempt (RFC 7591). Required when no static
|
|
77
|
+
* `clientId` is configured, and unused when one is.
|
|
78
|
+
*/
|
|
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>;
|
|
40
85
|
}
|
|
41
86
|
export interface KeycardInteractiveOptions {
|
|
42
87
|
/** The resource URL the authorization is scoped to. */
|
|
43
88
|
resource: string;
|
|
44
89
|
/** Keycard zone URL (issuer). Required unless `flow` is given. */
|
|
45
90
|
zoneUrl?: string;
|
|
46
|
-
/**
|
|
91
|
+
/**
|
|
92
|
+
* OAuth client the browser flow runs as.
|
|
93
|
+
*
|
|
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
|
|
97
|
+
* requires the authorization server to match `redirect_uri` by exact string
|
|
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.
|
|
100
|
+
*
|
|
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
|
|
104
|
+
* with `Unsupported client identifier prefix: urn`.
|
|
105
|
+
*/
|
|
47
106
|
clientId?: string;
|
|
48
|
-
/** Client secret, for a confidential client. Public clients omit it. */
|
|
107
|
+
/** Client secret, for a confidential static client. Public clients omit it. */
|
|
49
108
|
clientSecret?: string;
|
|
50
|
-
/**
|
|
109
|
+
/**
|
|
110
|
+
* Name shown on the zone's consent screen for a per-attempt client.
|
|
111
|
+
* Defaults to `connectionName`.
|
|
112
|
+
*/
|
|
113
|
+
clientName?: string;
|
|
114
|
+
/**
|
|
115
|
+
* Initial access token (RFC 7591 section 3.1) for a zone whose registration
|
|
116
|
+
* endpoint is authenticated. Unset for an open registration endpoint.
|
|
117
|
+
*/
|
|
118
|
+
initialAccessToken?: string;
|
|
119
|
+
/**
|
|
120
|
+
* Scopes requested in the authorization request, and the scopes a stored
|
|
121
|
+
* grant must cover to serve this connection.
|
|
122
|
+
*/
|
|
51
123
|
requestScopes?: string | readonly string[];
|
|
52
|
-
/**
|
|
124
|
+
/**
|
|
125
|
+
* Extra resources authorized alongside `resource`. The resulting grant
|
|
126
|
+
* serves every connection whose resource it covers.
|
|
127
|
+
*/
|
|
53
128
|
additionalResources?: readonly string[];
|
|
54
|
-
/**
|
|
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
|
+
*/
|
|
55
134
|
connectionName?: string;
|
|
56
|
-
/** Store for completed
|
|
57
|
-
tokens?:
|
|
135
|
+
/** Store for completed grants. Defaults to a process-local store. */
|
|
136
|
+
tokens?: GrantStore;
|
|
58
137
|
/** Web-flow seam. Replaces the zone calls, so tests take no network. */
|
|
59
138
|
flow?: WebAppFlow;
|
|
60
139
|
}
|
|
140
|
+
/** Forgets every defined connection name. For tests that define many. */
|
|
141
|
+
export declare function resetInteractiveDefinitions(): void;
|
|
61
142
|
/**
|
|
62
143
|
* Interactive connection auth backed by the zone's web authorization flow.
|
|
63
144
|
*
|
|
64
145
|
* The three callbacks eve drives:
|
|
65
146
|
*
|
|
66
|
-
* - `getToken` returns a token
|
|
67
|
-
*
|
|
68
|
-
*
|
|
69
|
-
*
|
|
70
|
-
*
|
|
71
|
-
*
|
|
72
|
-
*
|
|
73
|
-
*
|
|
74
|
-
*
|
|
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.
|
|
159
|
+
*
|
|
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.
|
|
165
|
+
*
|
|
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.
|
|
75
175
|
*
|
|
76
|
-
*
|
|
77
|
-
*
|
|
78
|
-
*
|
|
79
|
-
*
|
|
80
|
-
*
|
|
81
|
-
* rather than an endless loop: it settles each parked authorization once, and
|
|
82
|
-
* a `Required` thrown after a completed authorization ends the tool call.
|
|
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.
|
|
83
181
|
*
|
|
84
|
-
* Discovery is memoized per definition
|
|
85
|
-
*
|
|
182
|
+
* Discovery is memoized per definition. Registration is not, because the
|
|
183
|
+
* redirect URI it binds is different every time.
|
|
86
184
|
*/
|
|
87
185
|
export declare function interactive(options: KeycardInteractiveOptions): InteractiveAuthorizationDefinition<KeycardResumeState>;
|
|
88
|
-
/** A process-local store that drops
|
|
89
|
-
export declare function memoryAuthorizedTokenStore():
|
|
186
|
+
/** A process-local store that drops grants once they can no longer mint a token. */
|
|
187
|
+
export declare function memoryAuthorizedTokenStore(): GrantStore;
|
|
90
188
|
//# sourceMappingURL=interactive.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"interactive.d.ts","sourceRoot":"","sources":["../../src/interactive.ts"],"names":[],"mappings":"AAAA,OAAO,
|
|
1
|
+
{"version":3,"file":"interactive.d.ts","sourceRoot":"","sources":["../../src/interactive.ts"],"names":[],"mappings":"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"}
|
package/dist/esm/interactive.js
CHANGED
|
@@ -1,61 +1,218 @@
|
|
|
1
|
-
import { AuthProviderConfigurationError, AuthorizationDeniedError, beginAuthorization, completeAuthorization, fetchAuthorizationServerMetadata, 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
|
|
11
|
-
*
|
|
12
|
-
*
|
|
13
|
-
*
|
|
14
|
-
*
|
|
15
|
-
*
|
|
16
|
-
*
|
|
17
|
-
*
|
|
18
|
-
*
|
|
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.
|
|
30
|
+
*
|
|
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.
|
|
36
|
+
*
|
|
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.
|
|
19
46
|
*
|
|
20
|
-
*
|
|
21
|
-
*
|
|
22
|
-
*
|
|
23
|
-
*
|
|
24
|
-
*
|
|
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.
|
|
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.
|
|
27
52
|
*
|
|
28
|
-
* Discovery is memoized per definition
|
|
29
|
-
*
|
|
53
|
+
* Discovery is memoized per definition. Registration is not, because the
|
|
54
|
+
* redirect URI it binds is different every time.
|
|
30
55
|
*/
|
|
31
56
|
export function interactive(options) {
|
|
32
57
|
if (!options.resource || !options.resource.trim()) {
|
|
33
58
|
throw new AuthProviderConfigurationError("interactive requires a resource URL");
|
|
34
59
|
}
|
|
35
|
-
if (!options.flow &&
|
|
36
|
-
throw new AuthProviderConfigurationError("interactive requires zoneUrl
|
|
60
|
+
if (!options.flow && !options.zoneUrl) {
|
|
61
|
+
throw new AuthProviderConfigurationError("interactive requires zoneUrl, or an injected flow");
|
|
37
62
|
}
|
|
38
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
|
+
}
|
|
39
68
|
const tokens = options.tokens ?? memoryAuthorizedTokenStore();
|
|
40
|
-
const flow = options.flow ??
|
|
41
|
-
|
|
69
|
+
const flow = options.flow ??
|
|
70
|
+
zoneWebAppFlow(options.zoneUrl, {
|
|
71
|
+
...(options.initialAccessToken !== undefined
|
|
72
|
+
? { initialAccessToken: options.initialAccessToken }
|
|
73
|
+
: {}),
|
|
74
|
+
});
|
|
75
|
+
const staticClientId = options.clientId ?? "";
|
|
76
|
+
const clientName = options.clientName ?? connectionName;
|
|
42
77
|
const resources = [options.resource, ...(options.additionalResources ?? [])];
|
|
43
78
|
const scopes = splitScopes(options.requestScopes);
|
|
79
|
+
if (!staticClientId && !flow.register) {
|
|
80
|
+
throw new AuthProviderConfigurationError("interactive was given no clientId, so it registers a client per attempt, but the " +
|
|
81
|
+
"injected flow has no register()");
|
|
82
|
+
}
|
|
83
|
+
definedConnectionNames.add(connectionName);
|
|
84
|
+
const covers = (grant) => grant.resources.includes(options.resource) &&
|
|
85
|
+
scopes.every((scope) => grant.scopes.includes(scope));
|
|
86
|
+
/**
|
|
87
|
+
* The client this attempt runs as: the configured one, or a fresh public
|
|
88
|
+
* client whose single redirect URI is this attempt's callback.
|
|
89
|
+
*/
|
|
90
|
+
const clientForAttempt = async (callbackUrl) => {
|
|
91
|
+
if (staticClientId)
|
|
92
|
+
return staticClientId;
|
|
93
|
+
let registered;
|
|
94
|
+
try {
|
|
95
|
+
registered = await flow.register({
|
|
96
|
+
redirectUri: callbackUrl,
|
|
97
|
+
clientName,
|
|
98
|
+
...(scopes.length > 0 ? { scopes } : {}),
|
|
99
|
+
});
|
|
100
|
+
}
|
|
101
|
+
catch (cause) {
|
|
102
|
+
throw new AuthorizationFailedError(connectionName, {
|
|
103
|
+
message: cause instanceof Error
|
|
104
|
+
? `Registering the OAuth client for this authorization failed: ${cause.message}`
|
|
105
|
+
: "Registering the OAuth client for this authorization failed",
|
|
106
|
+
reason: FailureReason.ACQUISITION_FAILED,
|
|
107
|
+
retryable: true,
|
|
108
|
+
});
|
|
109
|
+
}
|
|
110
|
+
if (registered.clientSecret) {
|
|
111
|
+
throw new AuthorizationFailedError(connectionName, {
|
|
112
|
+
message: "The authorization server issued a confidential client for an authorization " +
|
|
113
|
+
"registered as public. Redeeming it would mean journaling a client secret into " +
|
|
114
|
+
"eve's durable resume state, so the attempt was abandoned instead. Configure a " +
|
|
115
|
+
"static clientId for this connection.",
|
|
116
|
+
reason: FailureReason.ACQUISITION_FAILED,
|
|
117
|
+
retryable: false,
|
|
118
|
+
});
|
|
119
|
+
}
|
|
120
|
+
return registered.clientId;
|
|
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
|
+
};
|
|
44
176
|
return {
|
|
45
177
|
principalType: "user",
|
|
46
|
-
|
|
178
|
+
/**
|
|
179
|
+
* No definition-level `displayName`: eve validates an authored connection's
|
|
180
|
+
* `auth` against a closed key list (`completeAuthorization`, `evict`,
|
|
181
|
+
* `getToken`, `principalType`, `startAuthorization`, `vercelConnect`) that
|
|
182
|
+
* omits it. The name rides on the challenge instead, where eve's
|
|
183
|
+
* `stampChallengeDisplayName` falls back to it.
|
|
184
|
+
*/
|
|
47
185
|
async getToken({ principal }) {
|
|
48
|
-
const key = storeKey(principal
|
|
49
|
-
const
|
|
50
|
-
|
|
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);
|
|
51
207
|
throw new AuthorizationRequiredError(connectionName);
|
|
52
208
|
}
|
|
53
|
-
return toTokenResult(
|
|
209
|
+
return toTokenResult(grant);
|
|
54
210
|
},
|
|
55
211
|
async startAuthorization({ principal, callbackUrl }) {
|
|
56
212
|
requireUser(principal, connectionName);
|
|
213
|
+
const attemptClientId = await clientForAttempt(callbackUrl);
|
|
57
214
|
const redirect = await flow.begin({
|
|
58
|
-
clientId,
|
|
215
|
+
clientId: attemptClientId,
|
|
59
216
|
redirectUri: callbackUrl,
|
|
60
217
|
resources,
|
|
61
218
|
...(scopes.length > 0 ? { scopes } : {}),
|
|
@@ -67,6 +224,7 @@ export function interactive(options) {
|
|
|
67
224
|
codeVerifier: redirect.codeVerifier,
|
|
68
225
|
resources: redirect.resources,
|
|
69
226
|
callbackUrl,
|
|
227
|
+
clientId: attemptClientId,
|
|
70
228
|
},
|
|
71
229
|
};
|
|
72
230
|
},
|
|
@@ -80,6 +238,9 @@ export function interactive(options) {
|
|
|
80
238
|
retryable: false,
|
|
81
239
|
});
|
|
82
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;
|
|
83
244
|
let response;
|
|
84
245
|
try {
|
|
85
246
|
response = await flow.complete({
|
|
@@ -88,7 +249,7 @@ export function interactive(options) {
|
|
|
88
249
|
codeVerifier: resume.codeVerifier,
|
|
89
250
|
clientId,
|
|
90
251
|
redirectUri: resume.callbackUrl || callbackUrl,
|
|
91
|
-
...(
|
|
252
|
+
...secretFor(clientId),
|
|
92
253
|
});
|
|
93
254
|
}
|
|
94
255
|
catch (cause) {
|
|
@@ -102,47 +263,59 @@ export function interactive(options) {
|
|
|
102
263
|
retryable: false,
|
|
103
264
|
});
|
|
104
265
|
}
|
|
105
|
-
const
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
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);
|
|
112
274
|
},
|
|
113
275
|
/**
|
|
114
|
-
* eve calls this after a rejected bearer
|
|
115
|
-
*
|
|
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.
|
|
116
279
|
*/
|
|
117
|
-
evict({ principal }) {
|
|
118
|
-
|
|
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)));
|
|
119
286
|
},
|
|
120
287
|
};
|
|
121
288
|
}
|
|
122
|
-
/** A process-local store that drops
|
|
289
|
+
/** A process-local store that drops grants once they can no longer mint a token. */
|
|
123
290
|
export function memoryAuthorizedTokenStore() {
|
|
124
|
-
const
|
|
291
|
+
const grants = new Map();
|
|
125
292
|
return {
|
|
126
|
-
|
|
127
|
-
const held =
|
|
293
|
+
async list(principal) {
|
|
294
|
+
const held = grants.get(principal);
|
|
128
295
|
if (!held)
|
|
129
|
-
return
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
296
|
+
return [];
|
|
297
|
+
const now = Date.now();
|
|
298
|
+
for (const [id, grant] of held) {
|
|
299
|
+
if (dead(grant, now))
|
|
300
|
+
held.delete(id);
|
|
133
301
|
}
|
|
134
|
-
return held;
|
|
302
|
+
return [...held.values()];
|
|
135
303
|
},
|
|
136
|
-
|
|
137
|
-
|
|
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);
|
|
138
311
|
},
|
|
139
|
-
|
|
140
|
-
|
|
312
|
+
async remove(principal, grantId) {
|
|
313
|
+
grants.get(principal)?.delete(grantId);
|
|
141
314
|
},
|
|
142
315
|
};
|
|
143
316
|
}
|
|
144
317
|
/** The default flow: the zone's web-app endpoints, with discovery memoized. */
|
|
145
|
-
function zoneWebAppFlow(issuer) {
|
|
318
|
+
function zoneWebAppFlow(issuer, options = {}) {
|
|
146
319
|
let metadata;
|
|
147
320
|
const discover = () => {
|
|
148
321
|
if (!metadata)
|
|
@@ -150,26 +323,88 @@ function zoneWebAppFlow(issuer) {
|
|
|
150
323
|
return metadata;
|
|
151
324
|
};
|
|
152
325
|
return {
|
|
153
|
-
async begin(
|
|
154
|
-
return beginAuthorization(issuer, {
|
|
326
|
+
async begin(beginOptions) {
|
|
327
|
+
return beginAuthorization(issuer, {
|
|
328
|
+
...beginOptions,
|
|
329
|
+
metadata: await discover(),
|
|
330
|
+
});
|
|
331
|
+
},
|
|
332
|
+
async complete(completeOptions) {
|
|
333
|
+
return completeAuthorization(issuer, {
|
|
334
|
+
...completeOptions,
|
|
335
|
+
metadata: await discover(),
|
|
336
|
+
});
|
|
155
337
|
},
|
|
156
|
-
async
|
|
157
|
-
return
|
|
338
|
+
async refresh(refreshOptions) {
|
|
339
|
+
return refreshAuthorization(issuer, {
|
|
340
|
+
...refreshOptions,
|
|
341
|
+
metadata: await discover(),
|
|
342
|
+
});
|
|
343
|
+
},
|
|
344
|
+
/**
|
|
345
|
+
* One public, PKCE-bound client per authorization, holding the single
|
|
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.
|
|
350
|
+
*/
|
|
351
|
+
async register({ redirectUri, clientName, scopes }) {
|
|
352
|
+
const registered = await registerClient(issuer, {
|
|
353
|
+
...(clientName !== undefined ? { clientName } : {}),
|
|
354
|
+
redirectUris: [redirectUri],
|
|
355
|
+
grantTypes: ["authorization_code", "refresh_token"],
|
|
356
|
+
responseTypes: ["code"],
|
|
357
|
+
tokenEndpointAuthMethod: "none",
|
|
358
|
+
...(scopes && scopes.length > 0 ? { scope: scopes.join(" ") } : {}),
|
|
359
|
+
}, options.initialAccessToken !== undefined
|
|
360
|
+
? { initialAccessToken: options.initialAccessToken }
|
|
361
|
+
: undefined);
|
|
362
|
+
return {
|
|
363
|
+
clientId: registered.clientId,
|
|
364
|
+
...(registered.clientSecret !== undefined
|
|
365
|
+
? { clientSecret: registered.clientSecret }
|
|
366
|
+
: {}),
|
|
367
|
+
};
|
|
158
368
|
},
|
|
159
369
|
};
|
|
160
370
|
}
|
|
161
|
-
|
|
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) {
|
|
162
400
|
if (principal.type !== "user")
|
|
163
|
-
return
|
|
164
|
-
return
|
|
401
|
+
return "app";
|
|
402
|
+
return principalKey(principal);
|
|
165
403
|
}
|
|
166
|
-
function toTokenResult(
|
|
404
|
+
function toTokenResult(grant) {
|
|
167
405
|
return {
|
|
168
|
-
token:
|
|
169
|
-
...(
|
|
170
|
-
...(token.providerSubject !== undefined
|
|
171
|
-
? { providerSubject: token.providerSubject }
|
|
172
|
-
: {}),
|
|
406
|
+
token: grant.accessToken,
|
|
407
|
+
...(grant.expiresAt !== undefined ? { expiresAt: grant.expiresAt } : {}),
|
|
173
408
|
};
|
|
174
409
|
}
|
|
175
410
|
function requireUser(principal, connectionName) {
|
|
@@ -185,6 +420,8 @@ function requireUser(principal, connectionName) {
|
|
|
185
420
|
function splitScopes(scopes) {
|
|
186
421
|
if (scopes === undefined)
|
|
187
422
|
return [];
|
|
188
|
-
return Array.isArray(scopes)
|
|
423
|
+
return Array.isArray(scopes)
|
|
424
|
+
? [...scopes]
|
|
425
|
+
: scopes.split(" ").filter(Boolean);
|
|
189
426
|
}
|
|
190
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":"AAAA,OAAO,EACL,8BAA8B,EAC9B,wBAAwB,EACxB,kBAAkB,EAClB,qBAAqB,EACrB,gCAAgC,EAChC,oBAAoB,EACpB,iBAAiB,EACjB,cAAc,EACd,kBAAkB,GAOnB,MAAM,kBAAkB,CAAC;AAQ1B,OAAO,EAAE,SAAS,EAAE,MAAM,aAAa,CAAC;AACxC,OAAO,EACL,wBAAwB,EACxB,0BAA0B,EAC1B,aAAa,GACd,MAAM,aAAa,CAAC;AACrB,OAAO,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAElD,yEAAyE;AACzE,MAAM,eAAe,GAAG,MAAM,CAAC;AAkJ/B,6EAA6E;AAC7E,MAAM,sBAAsB,GAAG,IAAI,GAAG,EAAU,CAAC;AAEjD,yEAAyE;AACzE,MAAM,UAAU,2BAA2B;IACzC,sBAAsB,CAAC,KAAK,EAAE,CAAC;AACjC,CAAC;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA0CG;AACH,MAAM,UAAU,WAAW,CACzB,OAAkC;IAElC,IAAI,CAAC,OAAO,CAAC,QAAQ,IAAI,CAAC,OAAO,CAAC,QAAQ,CAAC,IAAI,EAAE,EAAE,CAAC;QAClD,MAAM,IAAI,8BAA8B,CACtC,qCAAqC,CACtC,CAAC;IACJ,CAAC;IACD,IAAI,CAAC,OAAO,CAAC,IAAI,IAAI,CAAC,OAAO,CAAC,OAAO,EAAE,CAAC;QACtC,MAAM,IAAI,8BAA8B,CACtC,mDAAmD,CACpD,CAAC;IACJ,CAAC;IAED,MAAM,cAAc,GAAG,OAAO,CAAC,cAAc,IAAI,OAAO,CAAC,QAAQ,CAAC;IAClE,IAAI,sBAAsB,CAAC,GAAG,CAAC,cAAc,CAAC,EAAE,CAAC;QAC/C,MAAM,IAAI,8BAA8B,CACtC,+BAA+B,cAAc,wCAAwC;YACnF,6EAA6E,CAChF,CAAC;IACJ,CAAC;IACD,MAAM,MAAM,GAAG,OAAO,CAAC,MAAM,IAAI,0BAA0B,EAAE,CAAC;IAC9D,MAAM,IAAI,GACR,OAAO,CAAC,IAAI;QACZ,cAAc,CAAC,OAAO,CAAC,OAAQ,EAAE;YAC/B,GAAG,CAAC,OAAO,CAAC,kBAAkB,KAAK,SAAS;gBAC1C,CAAC,CAAC,EAAE,kBAAkB,EAAE,OAAO,CAAC,kBAAkB,EAAE;gBACpD,CAAC,CAAC,EAAE,CAAC;SACR,CAAC,CAAC;IACL,MAAM,cAAc,GAAG,OAAO,CAAC,QAAQ,IAAI,EAAE,CAAC;IAC9C,MAAM,UAAU,GAAG,OAAO,CAAC,UAAU,IAAI,cAAc,CAAC;IACxD,MAAM,SAAS,GAAG,CAAC,OAAO,CAAC,QAAQ,EAAE,GAAG,CAAC,OAAO,CAAC,mBAAmB,IAAI,EAAE,CAAC,CAAC,CAAC;IAC7E,MAAM,MAAM,GAAG,WAAW,CAAC,OAAO,CAAC,aAAa,CAAC,CAAC;IAElD,IAAI,CAAC,cAAc,IAAI,CAAC,IAAI,CAAC,QAAQ,EAAE,CAAC;QACtC,MAAM,IAAI,8BAA8B,CACtC,mFAAmF;YACjF,iCAAiC,CACpC,CAAC;IACJ,CAAC;IACD,sBAAsB,CAAC,GAAG,CAAC,cAAc,CAAC,CAAC;IAE3C,MAAM,MAAM,GAAG,CAAC,KAAsB,EAAW,EAAE,CACjD,KAAK,CAAC,SAAS,CAAC,QAAQ,CAAC,OAAO,CAAC,QAAQ,CAAC;QAC1C,MAAM,CAAC,KAAK,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,CAAC,MAAM,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC,CAAC;IAExD;;;OAGG;IACH,MAAM,gBAAgB,GAAG,KAAK,EAAE,WAAmB,EAAmB,EAAE;QACtE,IAAI,cAAc;YAAE,OAAO,cAAc,CAAC;QAC1C,IAAI,UAA4B,CAAC;QACjC,IAAI,CAAC;YACH,UAAU,GAAG,MAAM,IAAI,CAAC,QAAS,CAAC;gBAChC,WAAW,EAAE,WAAW;gBACxB,UAAU;gBACV,GAAG,CAAC,MAAM,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,EAAE,MAAM,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;aACzC,CAAC,CAAC;QACL,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,MAAM,IAAI,wBAAwB,CAAC,cAAc,EAAE;gBACjD,OAAO,EACL,KAAK,YAAY,KAAK;oBACpB,CAAC,CAAC,+DAA+D,KAAK,CAAC,OAAO,EAAE;oBAChF,CAAC,CAAC,4DAA4D;gBAClE,MAAM,EAAE,aAAa,CAAC,kBAAkB;gBACxC,SAAS,EAAE,IAAI;aAChB,CAAC,CAAC;QACL,CAAC;QACD,IAAI,UAAU,CAAC,YAAY,EAAE,CAAC;YAC5B,MAAM,IAAI,wBAAwB,CAAC,cAAc,EAAE;gBACjD,OAAO,EACL,6EAA6E;oBAC7E,gFAAgF;oBAChF,gFAAgF;oBAChF,sCAAsC;gBACxC,MAAM,EAAE,aAAa,CAAC,kBAAkB;gBACxC,SAAS,EAAE,KAAK;aACjB,CAAC,CAAC;QACL,CAAC;QACD,OAAO,UAAU,CAAC,QAAQ,CAAC;IAC7B,CAAC,CAAC;IAEF,gFAAgF;IAChF,MAAM,SAAS,GAAG,CAChB,QAAgB,EACiC,EAAE,CACnD,cAAc,IAAI,QAAQ,KAAK,cAAc,IAAI,OAAO,CAAC,YAAY;QACnE,CAAC,CAAC,EAAE,YAAY,EAAE,OAAO,CAAC,YAAY,EAAE;QACxC,CAAC,CAAC,EAAE,CAAC;IAET;;;OAGG;IACH,MAAM,YAAY,GAAG,KAAK,EACxB,SAAiB,EACjB,KAAiD,EACvB,EAAE;QAC5B,IAAI,QAAuB,CAAC;QAC5B,IAAI,CAAC;YACH,QAAQ,GAAG,MAAM,IAAI,CAAC,OAAQ,CAAC;gBAC7B,YAAY,EAAE,KAAK,CAAC,YAAY;gBAChC,QAAQ,EAAE,KAAK,CAAC,QAAQ;gBACxB,SAAS,EAAE,KAAK,CAAC,SAAS;gBAC1B,GAAG,CAAC,KAAK,CAAC,MAAM,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,EAAE,MAAM,EAAE,KAAK,CAAC,MAAM,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;gBAC5D,GAAG,SAAS,CAAC,KAAK,CAAC,QAAQ,CAAC;aAC7B,CAAC,CAAC;QACL,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,IACE,KAAK,YAAY,iBAAiB;gBAClC,KAAK,CAAC,SAAS,KAAK,eAAe,EACnC,CAAC;gBACD,qEAAqE;gBACrE,qEAAqE;gBACrE,gBAAgB;gBAChB,MAAM,OAAO,GAAG,CAAC,MAAM,MAAM,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC,CAAC,IAAI,CACjD,CAAC,SAAS,EAAE,EAAE,CAAC,SAAS,CAAC,EAAE,KAAK,KAAK,CAAC,EAAE,CACzC,CAAC;gBACF,IAAI,OAAO,IAAI,OAAO,CAAC,YAAY,KAAK,KAAK,CAAC,YAAY,EAAE,CAAC;oBAC3D,OAAO,OAAO,CAAC;gBACjB,CAAC;gBACD,MAAM,MAAM,CAAC,MAAM,CAAC,SAAS,EAAE,KAAK,CAAC,EAAE,CAAC,CAAC;gBACzC,MAAM,IAAI,0BAA0B,CAAC,cAAc,EAAE;oBACnD,OAAO,EACL,eAAe,cAAc,gDAAgD;wBAC7E,sBAAsB,KAAK,CAAC,OAAO,IAAI;iBAC1C,CAAC,CAAC;YACL,CAAC;YACD,MAAM,IAAI,wBAAwB,CAAC,cAAc,EAAE;gBACjD,OAAO,EACL,KAAK,YAAY,KAAK;oBACpB,CAAC,CAAC,gCAAgC,KAAK,CAAC,OAAO,EAAE;oBACjD,CAAC,CAAC,6BAA6B;gBACnC,MAAM,EAAE,aAAa,CAAC,kBAAkB;gBACxC,SAAS,EAAE,KAAK,YAAY,iBAAiB,CAAC,CAAC,CAAC,KAAK,CAAC,SAAS,CAAC,CAAC,CAAC,IAAI;aACvE,CAAC,CAAC;QACL,CAAC;QACD,MAAM,OAAO,GAAG,iBAAiB,CAAC,QAAQ,EAAE;YAC1C,EAAE,EAAE,KAAK,CAAC,EAAE;YACZ,QAAQ,EAAE,KAAK,CAAC,QAAQ;YACxB,SAAS,EAAE,KAAK,CAAC,SAAS;YAC1B,MAAM,EAAE,KAAK,CAAC,MAAM;YACpB,oEAAoE;YACpE,YAAY,EAAE,KAAK,CAAC,YAAY;SACjC,CAAC,CAAC;QACH,MAAM,MAAM,CAAC,GAAG,CAAC,SAAS,EAAE,OAAO,CAAC,CAAC;QACrC,OAAO,OAAO,CAAC;IACjB,CAAC,CAAC;IAEF,OAAO;QACL,aAAa,EAAE,MAAM;QACrB;;;;;;WAMG;QACH,KAAK,CAAC,QAAQ,CAAC,EAAE,SAAS,EAAE;YAC1B,MAAM,GAAG,GAAG,QAAQ,CAAC,SAAS,CAAC,CAAC;YAChC,MAAM,GAAG,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;YACvB,MAAM,IAAI,GAAG,CAAC,MAAM,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC;YACrD,uEAAuE;YACvE,0EAA0E;YAC1E,iBAAiB;YACjB,MAAM,MAAM,GAAG,IAAI,CAAC,MAAM,CAAC,CAAC,SAAS,EAAE,EAAE,CAAC,CAAC,IAAI,CAAC,SAAS,EAAE,GAAG,CAAC,CAAC,CAAC;YACjE,IAAI,KAAK,GACP,MAAM,CAAC,IAAI,CAAC,CAAC,SAAS,EAAE,EAAE,CAAC,CAAC,OAAO,CAAC,SAAS,EAAE,GAAG,CAAC,CAAC,IAAI,MAAM,CAAC,CAAC,CAAC,CAAC;YACpE,IAAI,CAAC,KAAK,EAAE,CAAC;gBACX,MAAM,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,MAAM,CAAC,MAAM,CAAC,GAAG,EAAE,KAAK,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC;gBACrE,MAAM,IAAI,0BAA0B,CAAC,cAAc,CAAC,CAAC;YACvD,CAAC;YACD,IAAI,UAAU,CAAC,KAAK,EAAE,GAAG,CAAC,IAAI,KAAK,CAAC,YAAY,IAAI,IAAI,CAAC,OAAO,EAAE,CAAC;gBACjE,KAAK,GAAG,MAAM,YAAY,CAAC,GAAG,EAAE;oBAC9B,GAAG,KAAK;oBACR,YAAY,EAAE,KAAK,CAAC,YAAY;iBACjC,CAAC,CAAC;YACL,CAAC;iBAAM,IAAI,OAAO,CAAC,KAAK,EAAE,GAAG,CAAC,EAAE,CAAC;gBAC/B,4CAA4C;gBAC5C,MAAM,MAAM,CAAC,MAAM,CAAC,GAAG,EAAE,KAAK,CAAC,EAAE,CAAC,CAAC;gBACnC,MAAM,IAAI,0BAA0B,CAAC,cAAc,CAAC,CAAC;YACvD,CAAC;YACD,OAAO,aAAa,CAAC,KAAK,CAAC,CAAC;QAC9B,CAAC;QACD,KAAK,CAAC,kBAAkB,CAAC,EAAE,SAAS,EAAE,WAAW,EAAE;YACjD,WAAW,CAAC,SAAS,EAAE,cAAc,CAAC,CAAC;YACvC,MAAM,eAAe,GAAG,MAAM,gBAAgB,CAAC,WAAW,CAAC,CAAC;YAC5D,MAAM,QAAQ,GAAG,MAAM,IAAI,CAAC,KAAK,CAAC;gBAChC,QAAQ,EAAE,eAAe;gBACzB,WAAW,EAAE,WAAW;gBACxB,SAAS;gBACT,GAAG,CAAC,MAAM,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,EAAE,MAAM,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;aACzC,CAAC,CAAC;YACH,OAAO;gBACL,SAAS,EAAE,EAAE,GAAG,EAAE,QAAQ,CAAC,GAAG,EAAE,WAAW,EAAE,cAAc,EAAE;gBAC7D,MAAM,EAAE;oBACN,KAAK,EAAE,QAAQ,CAAC,KAAK;oBACrB,YAAY,EAAE,QAAQ,CAAC,YAAY;oBACnC,SAAS,EAAE,QAAQ,CAAC,SAAS;oBAC7B,WAAW;oBACX,QAAQ,EAAE,eAAe;iBAC1B;aACF,CAAC;QACJ,CAAC;QACD,KAAK,CAAC,qBAAqB,CAAC,EAAE,SAAS,EAAE,WAAW,EAAE,MAAM,EAAE,QAAQ,EAAE;YACtE,WAAW,CAAC,SAAS,EAAE,cAAc,CAAC,CAAC;YACvC,IAAI,CAAC,MAAM,EAAE,CAAC;gBACZ,MAAM,IAAI,wBAAwB,CAAC,cAAc,EAAE;oBACjD,OAAO,EACL,wEAAwE;wBACxE,uCAAuC;oBACzC,MAAM,EAAE,aAAa,CAAC,gBAAgB;oBACtC,SAAS,EAAE,KAAK;iBACjB,CAAC,CAAC;YACL,CAAC;YAED,qEAAqE;YACrE,4CAA4C;YAC5C,MAAM,QAAQ,GAAG,MAAM,CAAC,QAAQ,IAAI,cAAc,CAAC;YACnD,IAAI,QAAuB,CAAC;YAC5B,IAAI,CAAC;gBACH,QAAQ,GAAG,MAAM,IAAI,CAAC,QAAQ,CAAC;oBAC7B,cAAc,EAAE,EAAE,GAAG,QAAQ,CAAC,MAAM,EAAE;oBACtC,KAAK,EAAE,MAAM,CAAC,KAAK;oBACnB,YAAY,EAAE,MAAM,CAAC,YAAY;oBACjC,QAAQ;oBACR,WAAW,EAAE,MAAM,CAAC,WAAW,IAAI,WAAW;oBAC9C,GAAG,SAAS,CAAC,QAAQ,CAAC;iBACvB,CAAC,CAAC;YACL,CAAC;YAAC,OAAO,KAAK,EAAE,CAAC;gBACf,MAAM,IAAI,wBAAwB,CAAC,cAAc,EAAE;oBACjD,OAAO,EACL,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,sBAAsB;oBACjE,MAAM,EACJ,KAAK,YAAY,wBAAwB;wBACvC,CAAC,CAAC,aAAa,CAAC,aAAa;wBAC7B,CAAC,CAAC,KAAK,YAAY,kBAAkB;4BACnC,CAAC,CAAC,aAAa,CAAC,gBAAgB;4BAChC,CAAC,CAAC,aAAa,CAAC,kBAAkB;oBACxC,SAAS,EAAE,KAAK;iBACjB,CAAC,CAAC;YACL,CAAC;YAED,MAAM,KAAK,GAAG,iBAAiB,CAAC,QAAQ,EAAE;gBACxC,EAAE,EAAE,MAAM,CAAC,UAAU,EAAE;gBACvB,QAAQ;gBACR,SAAS,EAAE,MAAM,CAAC,SAAS,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,SAAS,CAAC,CAAC,CAAC,SAAS;gBACrE,MAAM;aACP,CAAC,CAAC;YACH,MAAM,MAAM,CAAC,GAAG,CAAC,QAAQ,CAAC,SAAS,CAAC,EAAE,KAAK,CAAC,CAAC;YAC7C,OAAO,aAAa,CAAC,KAAK,CAAC,CAAC;QAC9B,CAAC;QACD;;;;WAIG;QACH,KAAK,CAAC,KAAK,CAAC,EAAE,SAAS,EAAE;YACvB,MAAM,GAAG,GAAG,QAAQ,CAAC,SAAS,CAAC,CAAC;YAChC,MAAM,IAAI,GAAG,MAAM,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;YACpC,MAAM,OAAO,CAAC,GAAG,CACf,IAAI;iBACD,MAAM,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,CAAC,SAAS,CAAC,QAAQ,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC;iBAC7D,GAAG,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,MAAM,CAAC,MAAM,CAAC,GAAG,EAAE,KAAK,CAAC,EAAE,CAAC,CAAC,CAChD,CAAC;QACJ,CAAC;KACF,CAAC;AACJ,CAAC;AAED,oFAAoF;AACpF,MAAM,UAAU,0BAA0B;IACxC,MAAM,MAAM,GAAG,IAAI,GAAG,EAAwC,CAAC;IAC/D,OAAO;QACL,KAAK,CAAC,IAAI,CAAC,SAAS;YAClB,MAAM,IAAI,GAAG,MAAM,CAAC,GAAG,CAAC,SAAS,CAAC,CAAC;YACnC,IAAI,CAAC,IAAI;gBAAE,OAAO,EAAE,CAAC;YACrB,MAAM,GAAG,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;YACvB,KAAK,MAAM,CAAC,EAAE,EAAE,KAAK,CAAC,IAAI,IAAI,EAAE,CAAC;gBAC/B,IAAI,IAAI,CAAC,KAAK,EAAE,GAAG,CAAC;oBAAE,IAAI,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC;YACxC,CAAC;YACD,OAAO,CAAC,GAAG,IAAI,CAAC,MAAM,EAAE,CAAC,CAAC;QAC5B,CAAC;QACD,KAAK,CAAC,GAAG,CAAC,SAAS,EAAE,KAAK;YACxB,IAAI,IAAI,GAAG,MAAM,CAAC,GAAG,CAAC,SAAS,CAAC,CAAC;YACjC,IAAI,CAAC,IAAI,EAAE,CAAC;gBACV,IAAI,GAAG,IAAI,GAAG,EAAE,CAAC;gBACjB,MAAM,CAAC,GAAG,CAAC,SAAS,EAAE,IAAI,CAAC,CAAC;YAC9B,CAAC;YACD,IAAI,CAAC,GAAG,CAAC,KAAK,CAAC,EAAE,EAAE,KAAK,CAAC,CAAC;QAC5B,CAAC;QACD,KAAK,CAAC,MAAM,CAAC,SAAS,EAAE,OAAO;YAC7B,MAAM,CAAC,GAAG,CAAC,SAAS,CAAC,EAAE,MAAM,CAAC,OAAO,CAAC,CAAC;QACzC,CAAC;KACF,CAAC;AACJ,CAAC;AAED,+EAA+E;AAC/E,SAAS,cAAc,CACrB,MAAc,EACd,UAA2C,EAAE;IAE7C,IAAI,QAA+D,CAAC;IACpE,MAAM,QAAQ,GAAG,GAA8C,EAAE;QAC/D,IAAI,CAAC,QAAQ;YAAE,QAAQ,GAAG,gCAAgC,CAAC,MAAM,CAAC,CAAC;QACnE,OAAO,QAAQ,CAAC;IAClB,CAAC,CAAC;IACF,OAAO;QACL,KAAK,CAAC,KAAK,CAAC,YAAY;YACtB,OAAO,kBAAkB,CAAC,MAAM,EAAE;gBAChC,GAAG,YAAY;gBACf,QAAQ,EAAE,MAAM,QAAQ,EAAE;aAC3B,CAAC,CAAC;QACL,CAAC;QACD,KAAK,CAAC,QAAQ,CAAC,eAAe;YAC5B,OAAO,qBAAqB,CAAC,MAAM,EAAE;gBACnC,GAAG,eAAe;gBAClB,QAAQ,EAAE,MAAM,QAAQ,EAAE;aAC3B,CAAC,CAAC;QACL,CAAC;QACD,KAAK,CAAC,OAAO,CAAC,cAAc;YAC1B,OAAO,oBAAoB,CAAC,MAAM,EAAE;gBAClC,GAAG,cAAc;gBACjB,QAAQ,EAAE,MAAM,QAAQ,EAAE;aAC3B,CAAC,CAAC;QACL,CAAC;QACD;;;;;;WAMG;QACH,KAAK,CAAC,QAAQ,CAAC,EAAE,WAAW,EAAE,UAAU,EAAE,MAAM,EAAE;YAChD,MAAM,UAAU,GAAG,MAAM,cAAc,CACrC,MAAM,EACN;gBACE,GAAG,CAAC,UAAU,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,UAAU,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;gBACnD,YAAY,EAAE,CAAC,WAAW,CAAC;gBAC3B,UAAU,EAAE,CAAC,oBAAoB,EAAE,eAAe,CAAC;gBACnD,aAAa,EAAE,CAAC,MAAM,CAAC;gBACvB,uBAAuB,EAAE,MAAM;gBAC/B,GAAG,CAAC,MAAM,IAAI,MAAM,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,EAAE,KAAK,EAAE,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;aACpE,EACD,OAAO,CAAC,kBAAkB,KAAK,SAAS;gBACtC,CAAC,CAAC,EAAE,kBAAkB,EAAE,OAAO,CAAC,kBAAkB,EAAE;gBACpD,CAAC,CAAC,SAAS,CACd,CAAC;YACF,OAAO;gBACL,QAAQ,EAAE,UAAU,CAAC,QAAQ;gBAC7B,GAAG,CAAC,UAAU,CAAC,YAAY,KAAK,SAAS;oBACvC,CAAC,CAAC,EAAE,YAAY,EAAE,UAAU,CAAC,YAAY,EAAE;oBAC3C,CAAC,CAAC,EAAE,CAAC;aACR,CAAC;QACJ,CAAC;KACF,CAAC;AACJ,CAAC;AAED;;;;GAIG;AACH,SAAS,iBAAiB,CACxB,QAAuB,EACvB,MAMC;IAED,MAAM,MAAM,GAAG,SAAS,CAAC,QAAQ,CAAC,SAAS,CAAC,CAAC;IAC7C,MAAM,YAAY,GAAG,QAAQ,CAAC,YAAY,IAAI,MAAM,CAAC,YAAY,CAAC;IAClE,OAAO;QACL,EAAE,EAAE,MAAM,CAAC,EAAE;QACb,WAAW,EAAE,QAAQ,CAAC,WAAW;QACjC,GAAG,CAAC,MAAM,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,SAAS,EAAE,MAAM,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;QACtD,GAAG,CAAC,YAAY,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,YAAY,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;QACvD,QAAQ,EAAE,MAAM,CAAC,QAAQ;QACzB,SAAS,EAAE,CAAC,GAAG,MAAM,CAAC,SAAS,CAAC;QAChC,MAAM,EAAE,QAAQ,CAAC,KAAK,CAAC,CAAC,CAAC,WAAW,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG,MAAM,CAAC,MAAM,CAAC;KAC1E,CAAC;AACJ,CAAC;AAED,SAAS,OAAO,CAAC,KAAsB,EAAE,GAAW;IAClD,OAAO,KAAK,CAAC,SAAS,KAAK,SAAS,IAAI,KAAK,CAAC,SAAS,IAAI,GAAG,CAAC;AACjE,CAAC;AAED,0EAA0E;AAC1E,SAAS,IAAI,CAAC,KAAsB,EAAE,GAAW;IAC/C,OAAO,OAAO,CAAC,KAAK,EAAE,GAAG,CAAC,IAAI,CAAC,KAAK,CAAC,YAAY,CAAC;AACpD,CAAC;AAED,SAAS,UAAU,CAAC,KAAsB,EAAE,GAAW;IACrD,OAAO,CACL,KAAK,CAAC,SAAS,KAAK,SAAS,IAAI,KAAK,CAAC,SAAS,GAAG,eAAe,IAAI,GAAG,CAC1E,CAAC;AACJ,CAAC;AAED,SAAS,QAAQ,CAAC,SAA8B;IAC9C,IAAI,SAAS,CAAC,IAAI,KAAK,MAAM;QAAE,OAAO,KAAK,CAAC;IAC5C,OAAO,YAAY,CAAC,SAAS,CAAC,CAAC;AACjC,CAAC;AAED,SAAS,aAAa,CAAC,KAAsB;IAC3C,OAAO;QACL,KAAK,EAAE,KAAK,CAAC,WAAW;QACxB,GAAG,CAAC,KAAK,CAAC,SAAS,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,SAAS,EAAE,KAAK,CAAC,SAAS,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;KACzE,CAAC;AACJ,CAAC;AAED,SAAS,WAAW,CAClB,SAA8B,EAC9B,cAAsB;IAEtB,IAAI,SAAS,CAAC,IAAI,KAAK,MAAM;QAAE,OAAO;IACtC,MAAM,IAAI,wBAAwB,CAAC,cAAc,EAAE;QACjD,OAAO,EACL,6EAA6E;YAC7E,wBAAwB;QAC1B,MAAM,EAAE,aAAa,CAAC,kBAAkB;QACxC,SAAS,EAAE,KAAK;KACjB,CAAC,CAAC;AACL,CAAC;AAED,SAAS,WAAW,CAAC,MAA8C;IACjE,IAAI,MAAM,KAAK,SAAS;QAAE,OAAO,EAAE,CAAC;IACpC,OAAO,KAAK,CAAC,OAAO,CAAC,MAAM,CAAC;QAC1B,CAAC,CAAC,CAAC,GAAG,MAAM,CAAC;QACb,CAAC,CAAE,MAAiB,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC;AACpD,CAAC"}
|
|
@@ -1,14 +1,19 @@
|
|
|
1
|
+
import type { ToolAuthOptions } from "eve/tools";
|
|
1
2
|
/**
|
|
2
3
|
* The part of eve's tool context this helper needs.
|
|
3
4
|
*
|
|
4
5
|
* Declared structurally rather than imported so nothing here loads eve at
|
|
5
6
|
* runtime. `ctx.requireAuth` never returns: it aborts the tool call and hands
|
|
6
7
|
* the connection's authorization strategy back to the runtime.
|
|
8
|
+
*
|
|
9
|
+
* The options are eve's own `ToolAuthOptions` — imported as a type, which is
|
|
10
|
+
* erased, so the structural property still holds. Taking the type from eve
|
|
11
|
+
* rather than restating it is deliberate: the previous hand-written shape
|
|
12
|
+
* accepted a `reason` field that eve does not have, and a call passing one
|
|
13
|
+
* failed to typecheck at the call site rather than here.
|
|
7
14
|
*/
|
|
8
15
|
export interface RequireAuthContext<Provider> {
|
|
9
|
-
requireAuth(provider: Provider, options?:
|
|
10
|
-
readonly reason?: string;
|
|
11
|
-
}): never;
|
|
16
|
+
requireAuth(provider: Provider, options?: ToolAuthOptions): never;
|
|
12
17
|
}
|
|
13
18
|
/**
|
|
14
19
|
* Maps a provider's rejection of the current credential onto
|
|
@@ -29,7 +34,5 @@ export interface RequireAuthContext<Provider> {
|
|
|
29
34
|
*/
|
|
30
35
|
export declare function requireAuthOnUnauthorized<Provider>(response: {
|
|
31
36
|
readonly status: number;
|
|
32
|
-
}, ctx: RequireAuthContext<Provider>, provider: Provider, options?:
|
|
33
|
-
readonly reason?: string;
|
|
34
|
-
}): void;
|
|
37
|
+
}, ctx: RequireAuthContext<Provider>, provider: Provider, options?: ToolAuthOptions): void;
|
|
35
38
|
//# sourceMappingURL=requireAuth.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"requireAuth.d.ts","sourceRoot":"","sources":["../../src/requireAuth.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"requireAuth.d.ts","sourceRoot":"","sources":["../../src/requireAuth.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,WAAW,CAAC;AAEjD;;;;;;;;;;;;GAYG;AACH,MAAM,WAAW,kBAAkB,CAAC,QAAQ;IAC1C,WAAW,CAAC,QAAQ,EAAE,QAAQ,EAAE,OAAO,CAAC,EAAE,eAAe,GAAG,KAAK,CAAC;CACnE;AAED;;;;;;;;;;;;;;;;GAgBG;AACH,wBAAgB,yBAAyB,CAAC,QAAQ,EAChD,QAAQ,EAAE;IAAE,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAA;CAAE,EACrC,GAAG,EAAE,kBAAkB,CAAC,QAAQ,CAAC,EACjC,QAAQ,EAAE,QAAQ,EAClB,OAAO,CAAC,EAAE,eAAe,GACxB,IAAI,CAGN"}
|
package/dist/esm/requireAuth.js
CHANGED
|
@@ -18,9 +18,6 @@
|
|
|
18
18
|
export function requireAuthOnUnauthorized(response, ctx, provider, options) {
|
|
19
19
|
if (response.status !== 401 && response.status !== 403)
|
|
20
20
|
return;
|
|
21
|
-
ctx.requireAuth(provider,
|
|
22
|
-
reason: options?.reason ??
|
|
23
|
-
`The provider rejected the connection credential with ${response.status}.`,
|
|
24
|
-
});
|
|
21
|
+
ctx.requireAuth(provider, options);
|
|
25
22
|
}
|
|
26
23
|
//# sourceMappingURL=requireAuth.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"requireAuth.js","sourceRoot":"","sources":["../../src/requireAuth.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"requireAuth.js","sourceRoot":"","sources":["../../src/requireAuth.ts"],"names":[],"mappings":"AAmBA;;;;;;;;;;;;;;;;GAgBG;AACH,MAAM,UAAU,yBAAyB,CACvC,QAAqC,EACrC,GAAiC,EACjC,QAAkB,EAClB,OAAyB;IAEzB,IAAI,QAAQ,CAAC,MAAM,KAAK,GAAG,IAAI,QAAQ,CAAC,MAAM,KAAK,GAAG;QAAE,OAAO;IAC/D,GAAG,CAAC,WAAW,CAAC,QAAQ,EAAE,OAAO,CAAC,CAAC;AACrC,CAAC"}
|
|
@@ -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.
|
|
3
|
+
"version": "0.3.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.
|
|
33
|
+
"@keycardai/oauth": "0.25.0"
|
|
34
34
|
},
|
|
35
35
|
"peerDependencies": {
|
|
36
|
-
"eve": ">=0.
|
|
36
|
+
"eve": ">=0.54.3 <0.55.0"
|
|
37
37
|
},
|
|
38
38
|
"devDependencies": {
|
|
39
39
|
"@jest/globals": "^30.0.4",
|
|
40
40
|
"@types/node": "^25.6.0",
|
|
41
|
-
"eve": "0.
|
|
41
|
+
"eve": "0.54.3",
|
|
42
42
|
"jest": "^30.0.4",
|
|
43
43
|
"ts-jest": "^29.4.7",
|
|
44
44
|
"typescript": "^5.8.3"
|