@cboxdk/id-js 0.19.0 → 0.21.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.
Files changed (42) hide show
  1. package/CHANGELOG.md +213 -0
  2. package/README.md +51 -3
  3. package/RELEASE-CANDIDATE.md +11 -0
  4. package/dist/agent.cjs +613 -0
  5. package/dist/agent.cjs.map +1 -0
  6. package/dist/agent.d.cts +400 -0
  7. package/dist/agent.d.ts +400 -0
  8. package/dist/agent.js +527 -0
  9. package/dist/agent.js.map +1 -0
  10. package/dist/api-keys-BE3R3q_A.d.ts +105 -0
  11. package/dist/api-keys-C8-Q4eFA.d.cts +105 -0
  12. package/dist/chunk-EVZ6RB3K.js +98 -0
  13. package/dist/chunk-EVZ6RB3K.js.map +1 -0
  14. package/dist/{chunk-YGLMLIKL.js → chunk-T5LCQOLS.js} +4 -22
  15. package/dist/chunk-T5LCQOLS.js.map +1 -0
  16. package/dist/chunk-VGQASHTI.js +22 -0
  17. package/dist/chunk-VGQASHTI.js.map +1 -0
  18. package/dist/decisions-C84Fzah4.d.ts +23 -0
  19. package/dist/decisions-DNd9UXwi.d.cts +23 -0
  20. package/dist/index.cjs +127 -14
  21. package/dist/index.cjs.map +1 -1
  22. package/dist/index.d.cts +1 -0
  23. package/dist/index.d.ts +1 -0
  24. package/dist/index.js +27 -6
  25. package/dist/index.js.map +1 -1
  26. package/dist/management.cjs +352 -19
  27. package/dist/management.cjs.map +1 -1
  28. package/dist/management.d.cts +994 -42
  29. package/dist/management.d.ts +994 -42
  30. package/dist/management.js +352 -19
  31. package/dist/management.js.map +1 -1
  32. package/dist/nextjs.d.cts +1 -1
  33. package/dist/nextjs.d.ts +1 -1
  34. package/dist/nextjs.js +2 -1
  35. package/dist/nextjs.js.map +1 -1
  36. package/dist/server.cjs +103 -9
  37. package/dist/server.cjs.map +1 -1
  38. package/dist/server.d.cts +3 -105
  39. package/dist/server.d.ts +3 -105
  40. package/dist/server.js +1 -0
  41. package/package.json +16 -3
  42. package/dist/chunk-YGLMLIKL.js.map +0 -1
@@ -0,0 +1,400 @@
1
+ import { JWK } from 'jose';
2
+ import { A as AuthenticationError, C as CboxIdError } from './errors-D61xljZE.js';
3
+ export { a as ConfigurationError } from './errors-D61xljZE.js';
4
+
5
+ /**
6
+ * RFC 8414 authorization server metadata, as Cbox ID publishes it at
7
+ * `{issuer}/.well-known/oauth-authorization-server`. Only the members this module reads are
8
+ * typed; the rest pass through.
9
+ */
10
+ interface AuthorizationServerMetadata {
11
+ issuer: string;
12
+ token_endpoint: string;
13
+ registration_endpoint?: string;
14
+ backchannel_authentication_endpoint?: string;
15
+ device_authorization_endpoint?: string;
16
+ backchannel_token_delivery_modes_supported?: string[];
17
+ backchannel_user_code_parameter_supported?: boolean;
18
+ grant_types_supported?: string[];
19
+ token_endpoint_auth_methods_supported?: string[];
20
+ token_endpoint_auth_signing_alg_values_supported?: string[];
21
+ [member: string]: unknown;
22
+ }
23
+ /** Transport options every call in this module takes. */
24
+ interface AgentRequestOptions {
25
+ /** A `fetch` to use instead of the global one (tests, proxies, instrumentation). */
26
+ fetch?: typeof fetch;
27
+ /** Per-request timeout in milliseconds. Default 10 000. */
28
+ timeoutMs?: number;
29
+ /** Abort the call (and, for the wait helpers, the whole wait). */
30
+ signal?: AbortSignal;
31
+ }
32
+ /** Where to find the server: its issuer, and optionally metadata you already discovered. */
33
+ interface AgentServerOptions extends AgentRequestOptions {
34
+ /** The Cbox ID issuer, e.g. `https://acme.cboxid.com`. Must be https (loopback excepted). */
35
+ issuer: string;
36
+ /**
37
+ * Metadata from {@link discoverAuthorizationServer}. Pass it to skip a discovery round
38
+ * trip per call; omitted, each call discovers it (the wait helpers discover once).
39
+ */
40
+ metadata?: AuthorizationServerMetadata;
41
+ }
42
+ /**
43
+ * Fetch and check the authorization server metadata (RFC 8414).
44
+ *
45
+ * The document's `issuer` must equal the one asked for (§3.3) — otherwise a host answering
46
+ * with another tenant's metadata would receive this client's assertions and codes.
47
+ */
48
+ declare function discoverAuthorizationServer(issuer: string, options?: AgentRequestOptions): Promise<AuthorizationServerMetadata>;
49
+
50
+ /** The client-assertion algorithms this module signs with. Cbox ID accepts both. */
51
+ type ClientKeyAlgorithm = 'ES256' | 'RS256';
52
+ /** A signing key pair for `private_key_jwt`, from {@link generateClientKeyPair}. */
53
+ interface ClientKeyPair {
54
+ alg: ClientKeyAlgorithm;
55
+ /** The RFC 7638 thumbprint of the public key, used as `kid`. */
56
+ kid: string;
57
+ /** The public JWK (with `kid`, `alg`, `use: 'sig'`) — what registration sends in `jwks`. */
58
+ publicJwk: JWK;
59
+ /**
60
+ * The private JWK. PERSIST THIS, and only this, somewhere the user alone can read
61
+ * (mode 0600, the OS keychain). It is the client's credential: whoever holds it is the
62
+ * client. Never log it, never commit it.
63
+ */
64
+ privateJwk: JWK;
65
+ /** The private key as a WebCrypto `CryptoKey`, ready to sign with. */
66
+ privateKey: CryptoKey;
67
+ }
68
+ /**
69
+ * How the client authenticates at the backchannel, device and token endpoints.
70
+ *
71
+ * - `private_key_jwt` (RFC 7523): a short-lived assertion signed with your private key.
72
+ * The right choice for a self-registered agent or CLI: nothing secret ever crosses the
73
+ * wire, and the server stores only the public key.
74
+ * - `client_secret_basic` / `client_secret_post`: a console-issued secret.
75
+ * - `none`: a public client names itself by `client_id` only. Fine for the device grant.
76
+ * For CIBA, Cbox ID accepts a keyless self-registered client only when the resource
77
+ * allows it (`dynamic_public_backchannel`); otherwise the answer is `invalid_target`.
78
+ * Prefer `private_key_jwt` for CIBA: a public `client_id` proves nothing, and CIBA has no front
79
+ * channel to bind the flow to.
80
+ */
81
+ type ClientAuth = {
82
+ method: 'private_key_jwt';
83
+ clientId: string;
84
+ /** A `CryptoKey`, or the private JWK you persisted from {@link generateClientKeyPair}. */
85
+ privateKey: CryptoKey | JWK;
86
+ /** Inferred from the key when omitted. */
87
+ alg?: ClientKeyAlgorithm;
88
+ /** Sent as the assertion's `kid`. Taken from a JWK's own `kid` when omitted. */
89
+ kid?: string;
90
+ } | {
91
+ method: 'client_secret_basic' | 'client_secret_post';
92
+ clientId: string;
93
+ clientSecret: string;
94
+ } | {
95
+ method: 'none';
96
+ clientId: string;
97
+ };
98
+ /**
99
+ * A fresh signing key pair for `private_key_jwt`, generated with WebCrypto (via `jose`), so
100
+ * it runs on Node, Deno, Bun and edge runtimes. ES256 by default — small keys, small
101
+ * signatures. The private key is extractable on purpose: the caller must persist it.
102
+ */
103
+ declare function generateClientKeyPair(alg?: ClientKeyAlgorithm): Promise<ClientKeyPair>;
104
+ /**
105
+ * A signed RFC 7523 client assertion: `iss` = `sub` = client id, `aud` = the token
106
+ * endpoint, a random `jti` (the server remembers it, so each assertion is single-use),
107
+ * `iat` now and `exp` at most 60 seconds later.
108
+ */
109
+ declare function createClientAssertion(auth: Extract<ClientAuth, {
110
+ method: 'private_key_jwt';
111
+ }>, audience: string, options?: {
112
+ now?: () => number;
113
+ lifetimeSeconds?: number;
114
+ }): Promise<string>;
115
+
116
+ /** The CIBA grant type (OpenID CIBA Core). */
117
+ declare const CIBA_GRANT_TYPE = "urn:openid:params:grant-type:ciba";
118
+ /** The device authorization grant type (RFC 8628). */
119
+ declare const DEVICE_CODE_GRANT_TYPE = "urn:ietf:params:oauth:grant-type:device_code";
120
+ interface RegisterAgentClientOptions extends AgentServerOptions {
121
+ /** Shown to the person approving, so make it recognisable: "Cbox Brain CLI on ada-mbp". */
122
+ clientName: string;
123
+ /** e.g. `[CIBA_GRANT_TYPE, 'refresh_token']` or `[DEVICE_CODE_GRANT_TYPE, 'refresh_token']`. */
124
+ grantTypes: string[];
125
+ /** The scope ceiling to register. A space-separated string or a list. */
126
+ scope?: string | string[];
127
+ /**
128
+ * `private_key_jwt` (default): a key pair is generated (or `keyPair` used) and the
129
+ * public half registered inline as `jwks`. `none`: a public client — the device grant,
130
+ * or CIBA where the resource allows keyless clients. `private_key_jwt` is recommended for CIBA.
131
+ */
132
+ tokenEndpointAuthMethod?: 'private_key_jwt' | 'none';
133
+ /** Algorithm for the generated key pair. Default ES256. */
134
+ alg?: ClientKeyAlgorithm;
135
+ /** Register an existing key pair instead of generating one. */
136
+ keyPair?: ClientKeyPair;
137
+ /** RFC 7591 §3 initial access token, when the instance requires one to register. */
138
+ initialAccessToken?: string;
139
+ /** Further RFC 7591 client metadata, sent as-is (e.g. `software_id`, `client_uri`). */
140
+ extraMetadata?: Record<string, unknown>;
141
+ }
142
+ interface RegisteredAgentClient {
143
+ clientId: string;
144
+ /** Present only if the server issued one; a `private_key_jwt` or `none` client has none. */
145
+ clientSecret: string | null;
146
+ /** RFC 7592 credential for reading/updating/deleting the registration. Persist it if you need that. */
147
+ registrationAccessToken: string | null;
148
+ registrationClientUri: string | null;
149
+ tokenEndpointAuthMethod: string;
150
+ grantTypes: string[];
151
+ scope: string | null;
152
+ /** The key pair registered, for `private_key_jwt`. Persist `keyPair.privateJwk`. */
153
+ keyPair: ClientKeyPair | null;
154
+ /** Ready to hand to {@link startBackchannel} / {@link startDeviceAuthorization}. */
155
+ auth: ClientAuth;
156
+ /** The full registration response. */
157
+ raw: Record<string, unknown>;
158
+ }
159
+ /**
160
+ * Register this agent or CLI as an OAuth client (RFC 7591 dynamic client registration).
161
+ *
162
+ * Do it once per installation and persist the result: `clientId` and, for
163
+ * `private_key_jwt`, `keyPair.privateJwk`. Re-registering on every run fills the
164
+ * environment's app list with copies.
165
+ *
166
+ * @throws ConfigurationError when the instance has dynamic registration switched off.
167
+ * @throws AgentGrantError (e.g. `invalid_client_metadata`) when the server refuses.
168
+ */
169
+ declare function registerAgentClient(options: RegisterAgentClientOptions): Promise<RegisteredAgentClient>;
170
+
171
+ /** Tokens from a completed CIBA or device grant. */
172
+ interface AgentTokens {
173
+ accessToken: string;
174
+ tokenType: string;
175
+ /** Seconds, when the server said. */
176
+ expiresIn: number | null;
177
+ refreshToken: string | null;
178
+ /**
179
+ * The id_token, when `openid` was granted — returned as-is, NOT verified here. Verify it
180
+ * with `CboxIdClient` (or `jose` against the JWKS) before trusting anything in it.
181
+ */
182
+ idToken: string | null;
183
+ scope: string | null;
184
+ /** The full token response. */
185
+ raw: Record<string, unknown>;
186
+ }
187
+ /** One poll's outcome. Final failures are thrown, not returned. */
188
+ type PollResult = {
189
+ status: 'complete';
190
+ tokens: AgentTokens;
191
+ } | {
192
+ status: 'pending';
193
+ }
194
+ /** Slow down: add 5 s to the interval, and wait at least `retryAfter` seconds if given. */
195
+ | {
196
+ status: 'slow_down';
197
+ retryAfter: number | null;
198
+ };
199
+ /** Options shared by the wait helpers. */
200
+ interface WaitOptions {
201
+ /** Replace the timer — tests pass a fake that records the waits. Must honour `signal`. */
202
+ sleep?: (ms: number, signal?: AbortSignal) => Promise<void>;
203
+ /** Clock in epoch milliseconds. Default `Date.now`. */
204
+ now?: () => number;
205
+ }
206
+ interface ClientOptions extends AgentServerOptions {
207
+ /** How the client authenticates. See {@link ClientAuth}. */
208
+ client: ClientAuth;
209
+ }
210
+ interface StartBackchannelOptions extends ClientOptions {
211
+ /** Who should approve: a Cbox ID user id, or a confirmed email address. */
212
+ loginHint: string;
213
+ /** Space-separated string or list. Bounded by the client's registered scopes. */
214
+ scope: string | string[];
215
+ /**
216
+ * Shown beside Approve. Put a {@link createBindingCode} code in it and print the same
217
+ * code locally. Required by Cbox ID for self-registered clients; at most 255 characters.
218
+ */
219
+ bindingMessage: string;
220
+ /**
221
+ * RFC 8707 resource indicator(s) — the API the token is for. Optional in the type, but
222
+ * REQUIRED by Cbox ID for self-registered clients.
223
+ * Its settings also decide whether a keyless (`none`) client may use CIBA at all.
224
+ */
225
+ resource?: string | string[];
226
+ /** Seconds the request may wait for approval (the server may shorten it). */
227
+ requestedExpiry?: number;
228
+ /** Echoed into the id_token, so you can bind it to this request. */
229
+ nonce?: string;
230
+ }
231
+ /** A started CIBA request. Persistable as JSON. */
232
+ interface BackchannelAuthorization {
233
+ authReqId: string;
234
+ expiresIn: number;
235
+ /** Seconds between polls. */
236
+ interval: number;
237
+ /** Epoch ms after which polling is pointless. */
238
+ expiresAt: number;
239
+ /** The resource(s) the request named, re-sent on every poll (the server checks they match). */
240
+ resource: string[];
241
+ }
242
+ /**
243
+ * Start a CIBA request (OpenID CIBA Core §7, poll mode): Cbox ID shows `bindingMessage` to
244
+ * the person named by `loginHint` and waits for Approve.
245
+ *
246
+ * `backchannel_user_code_parameter` is not supported by Cbox ID, so no user code is sent.
247
+ *
248
+ * @throws InvalidClientError, UnknownUserIdError, InvalidBindingMessageError,
249
+ * InvalidTargetError, SlowDownError, AgentGrantError.
250
+ */
251
+ declare function startBackchannel(options: StartBackchannelOptions): Promise<BackchannelAuthorization>;
252
+ interface PollBackchannelOptions extends ClientOptions {
253
+ authorization: Pick<BackchannelAuthorization, 'authReqId' | 'resource'>;
254
+ }
255
+ /**
256
+ * Poll the token endpoint once for a CIBA request.
257
+ *
258
+ * @throws AccessDeniedError, ExpiredTokenError, InvalidGrantError, InvalidTargetError,
259
+ * InvalidClientError, AgentGrantError.
260
+ */
261
+ declare function pollBackchannel(options: PollBackchannelOptions): Promise<PollResult>;
262
+ /**
263
+ * Poll until the person approves, and return the tokens.
264
+ *
265
+ * Waits `interval` seconds before each poll; on `slow_down` (or a 429) adds five seconds
266
+ * for good and waits at least `Retry-After`; keeps going on `authorization_pending`; stops
267
+ * on anything final. Throws {@link ExpiredTokenError} once `expiresAt` passes and
268
+ * {@link GrantCancelledError} when `signal` fires — wire it to Ctrl-C.
269
+ */
270
+ declare function waitForBackchannelToken(options: PollBackchannelOptions & WaitOptions & {
271
+ authorization: BackchannelAuthorization;
272
+ }): Promise<AgentTokens>;
273
+ interface StartDeviceAuthorizationOptions extends ClientOptions {
274
+ scope?: string | string[];
275
+ /** RFC 8707 resource indicator(s). */
276
+ resource?: string | string[];
277
+ }
278
+ /** A started device authorization. Persistable as JSON. */
279
+ interface DeviceGrantAuthorization {
280
+ deviceCode: string;
281
+ /** Show this to the person. */
282
+ userCode: string;
283
+ /** Where they enter it. */
284
+ verificationUri: string;
285
+ /** The same page with the code filled in — good for a QR code or `open`. */
286
+ verificationUriComplete: string | null;
287
+ expiresIn: number;
288
+ interval: number;
289
+ expiresAt: number;
290
+ resource: string[];
291
+ }
292
+ /**
293
+ * Start the device authorization grant: you get a `userCode` to show and a
294
+ * `verificationUri` for the person to open on any device.
295
+ *
296
+ * @throws InvalidClientError, InvalidTargetError, SlowDownError, AgentGrantError.
297
+ */
298
+ declare function startDeviceAuthorization(options: StartDeviceAuthorizationOptions): Promise<DeviceGrantAuthorization>;
299
+ interface PollDeviceAuthorizationOptions extends ClientOptions {
300
+ authorization: Pick<DeviceGrantAuthorization, 'deviceCode' | 'resource'>;
301
+ }
302
+ /** Poll the token endpoint once for a device authorization. */
303
+ declare function pollDeviceAuthorization(options: PollDeviceAuthorizationOptions): Promise<PollResult>;
304
+ /** Poll until the person approves the device code. Same rules as {@link waitForBackchannelToken}. */
305
+ declare function waitForDeviceToken(options: PollDeviceAuthorizationOptions & WaitOptions & {
306
+ authorization: DeviceGrantAuthorization;
307
+ }): Promise<AgentTokens>;
308
+ interface RefreshAgentTokensOptions extends ClientOptions {
309
+ refreshToken: string;
310
+ /** Narrow the scope (never widen it). */
311
+ scope?: string | string[];
312
+ /** RFC 8707 resource indicator(s) for the new access token. */
313
+ resource?: string | string[];
314
+ }
315
+ /**
316
+ * Exchange a refresh token, authenticating the same way the grant did (including
317
+ * `private_key_jwt`). Cbox ID rotates refresh tokens and revokes the family on reuse, so
318
+ * ALWAYS persist the returned `refreshToken` and discard the old one.
319
+ *
320
+ * @throws InvalidGrantError when the refresh token is no longer valid — sign in again.
321
+ */
322
+ declare function refreshAgentTokens(options: RefreshAgentTokensOptions): Promise<AgentTokens>;
323
+
324
+ /**
325
+ * Uppercase letters and digits a person cannot confuse when reading them off one screen
326
+ * and matching them on another: no 0/O, 1/I/L, 5/S, 2/Z, 8/B.
327
+ */
328
+ declare const BINDING_CODE_ALPHABET = "ACDEFGHJKMNPQRTUVWXY34679";
329
+ /**
330
+ * A short random code for a CIBA `binding_message`, e.g. `K7QM`.
331
+ *
332
+ * Show it in your terminal and put it in the binding message; Cbox ID shows the message
333
+ * beside Approve, and the person approves only when the two match. That is what stops a
334
+ * prompt somebody else triggered from being approved by reflex. Cbox ID requires a
335
+ * binding message from self-registered clients.
336
+ *
337
+ * Uniform over the alphabet (rejection sampling, WebCrypto randomness).
338
+ */
339
+ declare function createBindingCode(length?: number): string;
340
+
341
+ /**
342
+ * A CIBA, device-grant or registration request was refused with an OAuth error.
343
+ *
344
+ * Extends {@link AuthenticationError}, so `error`, `errorDescription`, `status` and
345
+ * `retryAfter` read the same as on every other back-channel failure in this SDK, and a
346
+ * caller already catching `AuthenticationError` keeps working. Branch on the subclass (or
347
+ * on `error`), never on the message.
348
+ *
349
+ * The REQUEST is never part of the error: these calls carry client assertions, secrets and
350
+ * device codes, and production CLIs log what they throw.
351
+ */
352
+ declare class AgentGrantError extends AuthenticationError {
353
+ }
354
+ /** The person declined (`access_denied`). Final — do not poll again. */
355
+ declare class AccessDeniedError extends AgentGrantError {
356
+ }
357
+ /**
358
+ * The `auth_req_id` or `device_code` expired before anyone approved it (`expired_token`).
359
+ * Also thrown locally when the wait outlives the request's `expires_in`. Start again.
360
+ */
361
+ declare class ExpiredTokenError extends AgentGrantError {
362
+ }
363
+ /** The `auth_req_id`, `device_code` or refresh token is not valid (`invalid_grant`). */
364
+ declare class InvalidGrantError extends AgentGrantError {
365
+ }
366
+ /**
367
+ * The `resource` (RFC 8707) is not one this client may ask for, the poll named a
368
+ * different resource than the request that started it, or the resource lets
369
+ * self-registered clients use CIBA only with `private_key_jwt` and this one is keyless
370
+ * (`invalid_target`).
371
+ */
372
+ declare class InvalidTargetError extends AgentGrantError {
373
+ }
374
+ /**
375
+ * Client authentication failed (`invalid_client`): an unknown `client_id`, a bad secret, an
376
+ * assertion signed by a key the server does not hold, or a replayed `jti`.
377
+ */
378
+ declare class InvalidClientError extends AgentGrantError {
379
+ }
380
+ /** The `login_hint` names nobody the server can reach (`unknown_user_id`). */
381
+ declare class UnknownUserIdError extends AgentGrantError {
382
+ }
383
+ /**
384
+ * The `binding_message` is missing where the server requires one (self-registered clients),
385
+ * or too long to show beside Approve (`invalid_binding_message`).
386
+ */
387
+ declare class InvalidBindingMessageError extends AgentGrantError {
388
+ }
389
+ /**
390
+ * The server asked us to slow down (`slow_down`, or HTTP 429). `retryAfter` carries the
391
+ * `Retry-After` seconds when the server sent them. The wait helpers absorb this themselves;
392
+ * it is thrown only from a call that does not loop (registration, starting a flow).
393
+ */
394
+ declare class SlowDownError extends AgentGrantError {
395
+ }
396
+ /** The caller aborted the wait (its `AbortSignal` fired). */
397
+ declare class GrantCancelledError extends CboxIdError {
398
+ }
399
+
400
+ export { AccessDeniedError, AgentGrantError, type AgentRequestOptions, type AgentServerOptions, type AgentTokens, AuthenticationError, type AuthorizationServerMetadata, BINDING_CODE_ALPHABET, type BackchannelAuthorization, CIBA_GRANT_TYPE, CboxIdError, type ClientAuth, type ClientKeyAlgorithm, type ClientKeyPair, DEVICE_CODE_GRANT_TYPE, type DeviceGrantAuthorization, ExpiredTokenError, GrantCancelledError, InvalidBindingMessageError, InvalidClientError, InvalidGrantError, InvalidTargetError, type PollBackchannelOptions, type PollDeviceAuthorizationOptions, type PollResult, type RefreshAgentTokensOptions, type RegisterAgentClientOptions, type RegisteredAgentClient, SlowDownError, type StartBackchannelOptions, type StartDeviceAuthorizationOptions, UnknownUserIdError, type WaitOptions, createBindingCode, createClientAssertion, discoverAuthorizationServer, generateClientKeyPair, pollBackchannel, pollDeviceAuthorization, refreshAgentTokens, registerAgentClient, startBackchannel, startDeviceAuthorization, waitForBackchannelToken, waitForDeviceToken };