@cboxdk/id-js 0.15.1 → 0.17.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.
@@ -0,0 +1,316 @@
1
+ /**
2
+ * The membership tier a person holds in the organization a token is bound to — the
3
+ * `org_role` claim. Coarse on purpose: it says who may administer the organization
4
+ * itself (invite, bill, delete). What they may do inside YOUR app is `roles` /
5
+ * `permissions`, which your app declares and Cbox ID assigns.
6
+ */
7
+ type OrganizationRole = 'owner' | 'admin' | 'developer' | 'member' | 'viewer';
8
+ /** The organization a token is bound to: the `org`, `org_name` and `org_role` claims. */
9
+ interface CboxActiveOrganization {
10
+ /** The stable organization id (`org`). */
11
+ id: string;
12
+ /** Its display name (`org_name`), when the instance sent one. */
13
+ name: string | null;
14
+ /**
15
+ * The person's membership tier in it (`org_role`). Null when the claim is absent, or
16
+ * carries a tier this SDK version does not know — an unrecognised tier is never
17
+ * guessed upward into one that grants something.
18
+ */
19
+ role: OrganizationRole | null;
20
+ }
21
+ /**
22
+ * Who is actually driving a delegated session — the RFC 8693 §4.1 `act` claim. Cbox ID
23
+ * sets it on the tokens of a SUPPORT SESSION: a staff member acting as one of your users,
24
+ * with a stated reason, for at most an hour, with no refresh token.
25
+ *
26
+ * `sub` is the actor's subject id. It is null when an `act` claim is present but not in
27
+ * the shape RFC 8693 describes — the token is still acted, and saying so matters more
28
+ * than knowing by whom (see {@link isSupportSession}).
29
+ */
30
+ interface CboxActor {
31
+ sub: string | null;
32
+ /** The prior actor, when delegation was chained (RFC 8693 §4.1 nested `act`). */
33
+ actor: CboxActor | null;
34
+ }
35
+ /**
36
+ * Anything the helpers below can read claims from: a {@link CboxUser} from sign-in, or a
37
+ * claim set you verified yourself — an access token's payload on a resource server, say.
38
+ */
39
+ type ClaimSource = CboxUser | Readonly<Record<string, unknown>>;
40
+ /**
41
+ * The organization this session is bound to, or null when it is bound to none.
42
+ *
43
+ * ```ts
44
+ * const org = organization(user);
45
+ * if (org?.role === 'owner') showBilling();
46
+ * ```
47
+ */
48
+ declare function organization(source: ClaimSource): CboxActiveOrganization | null;
49
+ /**
50
+ * The actor behind a support session (`act`), or null for an ordinary session in which
51
+ * the person is acting as themselves.
52
+ */
53
+ declare function actor(source: ClaimSource): CboxActor | null;
54
+ /**
55
+ * Whether somebody other than the signed-in person is driving this session — a staff
56
+ * member in a support session (the token carries `act`).
57
+ *
58
+ * FAIL-CLOSED. Any `act` claim at all counts, including one whose shape this SDK cannot
59
+ * read: the check exists so an app can show a banner and refuse the things a helper
60
+ * should never do on somebody's behalf (change their password, move their money), and a
61
+ * malformed claim is not evidence that nobody else is at the keyboard.
62
+ */
63
+ declare function isSupportSession(source: ClaimSource): boolean;
64
+ /**
65
+ * The Cbox ID sign-in session this token came from — the ID Token's `sid` claim — or null
66
+ * when the instance sent none.
67
+ *
68
+ * Store it with your own session: an OIDC Back-Channel Logout token names the session it
69
+ * ends by this value, and matching on it is how you end the right one (rather than every
70
+ * session the person has) when they sign out of Cbox ID elsewhere.
71
+ */
72
+ declare function sessionId(source: ClaimSource): string | null;
73
+ /** The app roles this session holds — the `roles` claim; empty when there are none. */
74
+ declare function roles(source: ClaimSource): string[];
75
+ /**
76
+ * The permissions this session holds — the `permissions` claim, already expanded from
77
+ * `roles` by Cbox ID; empty when there are none.
78
+ */
79
+ declare function permissions(source: ClaimSource): string[];
80
+ /** Whether the session holds `role`. Exact match; no wildcards. */
81
+ declare function hasRole(source: ClaimSource, role: string): boolean;
82
+ /**
83
+ * Whether the session holds `permission` (`feature:action`). Exact match; no wildcards
84
+ * — a claim of `invoices:*` does not grant `invoices:delete`, because nothing on the
85
+ * issuing side ever mints one.
86
+ */
87
+ declare function hasPermission(source: ClaimSource, permission: string): boolean;
88
+
89
+ /** Configuration for a {@link CboxIdClient}. */
90
+ interface CboxIdConfig {
91
+ /**
92
+ * Base URL (issuer) of the Cbox ID instance, e.g. `https://id.acme.com`. Every
93
+ * endpoint is discovered from `{issuer}/.well-known/openid-configuration`, so this
94
+ * is usually the only endpoint you configure.
95
+ */
96
+ issuer: string;
97
+ /** Your registered OAuth client id. */
98
+ clientId: string;
99
+ /**
100
+ * Your client secret. Required for confidential (server-side) apps, machine
101
+ * tokens and introspection. Omit for public clients (SPA/native) that only do
102
+ * PKCE login.
103
+ */
104
+ clientSecret?: string;
105
+ /**
106
+ * Your callback URL — must exactly match one registered on the client.
107
+ *
108
+ * OPTIONAL, because not every flow has one. The device grant (RFC 8628) exists
109
+ * precisely for programs with no browser to be returned to, so a CLI has none to give;
110
+ * requiring it here made every CLI invent `'http://localhost'` and note that it is
111
+ * unused. It is required by {@link CboxIdClient.createAuthorizationRequest} and
112
+ * {@link CboxIdClient.authenticate}, which is where its absence actually breaks
113
+ * something.
114
+ */
115
+ redirectUri?: string;
116
+ /** Scopes requested at login. Defaults to `['openid', 'profile', 'email']`. */
117
+ scopes?: string[];
118
+ /**
119
+ * Path of the instance's hosted account page that {@link CboxIdClient.profileUrl}
120
+ * points at. Defaults to `/account`, the person's own account area. (`/settings` is
121
+ * the organization's settings page, for its administrators.)
122
+ */
123
+ accountPath?: string;
124
+ /** Timeout (ms) for back-channel HTTP calls. Defaults to `10000`. */
125
+ timeoutMs?: number;
126
+ /** How long (ms) the discovery document is cached. Defaults to `3600000` (1h). */
127
+ cacheTtlMs?: number;
128
+ /**
129
+ * Leeway (seconds) when checking the id_token's `auth_time` against the `maxAge` you
130
+ * requested at login. Defaults to `60`.
131
+ *
132
+ * Some slack is required, not optional: `maxAge` bounds the age of the
133
+ * AUTHENTICATION, but `auth_time` is read after a browser redirect and a token
134
+ * exchange, so even a just-completed re-authentication is already several seconds
135
+ * old — and the RP's clock and the instance's need not agree. Sixty seconds absorbs
136
+ * that while still catching what this check exists for: a session hours or days old
137
+ * being passed off as fresh.
138
+ */
139
+ authTimeToleranceSeconds?: number;
140
+ }
141
+ /** The OIDC discovery document fields this SDK uses. */
142
+ interface DiscoveryDocument {
143
+ issuer: string;
144
+ authorization_endpoint: string;
145
+ token_endpoint: string;
146
+ jwks_uri: string;
147
+ userinfo_endpoint?: string;
148
+ introspection_endpoint?: string;
149
+ revocation_endpoint?: string;
150
+ end_session_endpoint?: string;
151
+ device_authorization_endpoint?: string;
152
+ }
153
+ /**
154
+ * A pending device authorization (RFC 8628) — what a CLI shows the person while it waits.
155
+ */
156
+ interface DeviceAuthorization {
157
+ /** The secret this program polls with. Never show it to the person. */
158
+ deviceCode: string;
159
+ /** The short code the person types on the verification page. */
160
+ userCode: string;
161
+ /** Where the person goes to approve. Print this. */
162
+ verificationUri: string;
163
+ /** The same page with the code filled in — for a clickable link or a QR code. */
164
+ verificationUriComplete: string | null;
165
+ /** Seconds until the code stops being valid. */
166
+ expiresIn: number;
167
+ /** The minimum seconds between polls. Never poll faster; the server will say so. */
168
+ interval: number;
169
+ }
170
+ /**
171
+ * RFC 7009 `token_type_hint`: which token store the server should search first.
172
+ * Only a hint — the server must still find the token if the hint is wrong.
173
+ */
174
+ type TokenTypeHint = 'access_token' | 'refresh_token';
175
+ /**
176
+ * An OIDC `prompt` value Cbox ID understands. The first four are OIDC Core §3.1.2.1; the
177
+ * last two are Cbox ID's organization steps:
178
+ *
179
+ * - `select_organization` — always show the hosted organization picker, even to someone
180
+ * in a single organization.
181
+ * - `create_organization` — the hosted "create a team" step: the person creates an
182
+ * organization, becomes its owner, and the sign-in continues bound to it.
183
+ */
184
+ type AuthorizationPrompt = 'none' | 'login' | 'consent' | 'select_account' | 'select_organization' | 'create_organization';
185
+ /** Options for {@link CboxIdClient.createAuthorizationRequest}. */
186
+ interface AuthorizationRequestOptions {
187
+ /** Scopes for this sign-in; defaults to the configured set. */
188
+ scopes?: string[];
189
+ /** Overrides the configured callback for this sign-in. */
190
+ redirectUri?: string;
191
+ /** Your own `state`; a random one is generated when omitted. */
192
+ state?: string;
193
+ /**
194
+ * One prompt, or several (sent space-separated). `none` cannot be combined with
195
+ * anything else — OIDC Core §3.1.2.1 makes that an error at the server, so it is
196
+ * refused here, where the stack trace still points at your code.
197
+ */
198
+ prompt?: AuthorizationPrompt | readonly AuthorizationPrompt[];
199
+ /** Prefills the email on the sign-in page (`login_hint`). */
200
+ loginHint?: string;
201
+ /** Demand an authentication no older than this many seconds (`max_age`). */
202
+ maxAge?: number;
203
+ /**
204
+ * Bind this sign-in to one organization (`organization`). The person must hold an
205
+ * active membership in it; if they do not, the callback carries
206
+ * `error=access_denied` and {@link CboxIdClient.authenticate} throws an
207
+ * `AuthenticationError` whose `error` is `'access_denied'`.
208
+ *
209
+ * This is how an app switches organization: a new authorization bound to the other
210
+ * one. See {@link CboxIdClient.switchOrganization}.
211
+ */
212
+ organization?: string;
213
+ /**
214
+ * Preselect an organization in the hosted picker (`organization_hint`) without binding
215
+ * to it — the person can still choose another. Pair it with
216
+ * `prompt: 'select_organization'` to always show the picker with your guess on top.
217
+ */
218
+ organizationHint?: string;
219
+ }
220
+ /**
221
+ * The values {@link CboxIdClient.createAuthorizationRequest} returns. Persist
222
+ * `state`, `codeVerifier` and `nonce` (e.g. in signed, httpOnly cookies) and hand
223
+ * them back to {@link CboxIdClient.authenticate} on the callback.
224
+ */
225
+ interface AuthorizationRequest {
226
+ /** The URL to redirect the user to. */
227
+ url: string;
228
+ state: string;
229
+ codeVerifier: string;
230
+ nonce: string;
231
+ /**
232
+ * Echoed back when you passed `maxAge`. Persist it with the rest and hand it to
233
+ * {@link CboxIdClient.authenticate}, which then verifies the id_token's `auth_time`
234
+ * against it — a step-up nobody checks is not a step-up.
235
+ */
236
+ maxAge?: number;
237
+ /**
238
+ * Echoed back when you passed `organization`. Persist it and hand it to
239
+ * {@link CboxIdClient.authenticate}, which then refuses tokens bound to any other
240
+ * organization — see {@link StoredAuthState.organization}.
241
+ */
242
+ organization?: string;
243
+ }
244
+ /** The raw token-endpoint response. */
245
+ interface TokenResponse {
246
+ access_token: string;
247
+ token_type?: string;
248
+ id_token?: string;
249
+ refresh_token?: string;
250
+ expires_in?: number;
251
+ scope?: string;
252
+ }
253
+ /**
254
+ * The tokens returned by {@link CboxIdClient.refresh}. Cbox ID ROTATES refresh
255
+ * tokens and detects reuse, so `refreshToken` is a NEW value — store it and discard
256
+ * the one you presented; replaying a rotated token revokes the whole family.
257
+ */
258
+ interface RefreshedTokens {
259
+ accessToken: string;
260
+ refreshToken: string;
261
+ idToken: string | null;
262
+ expiresIn: number;
263
+ scope: string | null;
264
+ }
265
+ /** One organization a user belongs to, from the `organizations` claim when present. */
266
+ interface CboxOrganization {
267
+ id: string;
268
+ name: string;
269
+ /** The member's role in this organization, when the claim carries it. */
270
+ role?: string | null;
271
+ }
272
+ /**
273
+ * The authenticated Cbox ID user. `id` is the stable opaque subject (`sub`) you key
274
+ * your local account on. `claims` is the full verified id_token + userinfo claim
275
+ * set; the named fields are conveniences over it.
276
+ */
277
+ interface CboxUser {
278
+ id: string;
279
+ email: string | null;
280
+ name: string | null;
281
+ /** The active organization's id (`org` claim). Same as `organization?.id`. */
282
+ organizationId: string | null;
283
+ /**
284
+ * The organization this session is bound to — id, name and the person's membership
285
+ * tier in it (`org`, `org_name`, `org_role`) — or null when it is bound to none.
286
+ */
287
+ organization: CboxActiveOrganization | null;
288
+ /** App roles held in this session (`roles` claim); empty when there are none. */
289
+ roles: string[];
290
+ /** Permissions held in this session (`permissions` claim); empty when there are none. */
291
+ permissions: string[];
292
+ /**
293
+ * Set when this is a SUPPORT SESSION — a staff member acting as this person (the RFC
294
+ * 8693 `act` claim). Null for an ordinary sign-in. Show it: see `isSupportSession()`.
295
+ */
296
+ actor: CboxActor | null;
297
+ /**
298
+ * The Cbox ID sign-in session (the ID Token's `sid`), or null when none was sent. Keep
299
+ * it with your session to match a back-channel logout to it. See `sessionId()`.
300
+ */
301
+ sessionId: string | null;
302
+ /**
303
+ * The organizations this user belongs to — the UserInfo `organizations` claim, which
304
+ * Cbox ID only sends when you requested the `organizations` scope (it lists every
305
+ * organization the person is in, so a plain `profile` sign-in does not get it).
306
+ * Undefined when the claim is absent. Pass straight to `<OrganizationSwitcher>`.
307
+ */
308
+ organizations?: CboxOrganization[];
309
+ claims: Record<string, unknown>;
310
+ accessToken: string;
311
+ refreshToken: string | null;
312
+ idToken: string | null;
313
+ expiresIn: number;
314
+ }
315
+
316
+ export { type AuthorizationRequestOptions as A, type CboxUser as C, type DeviceAuthorization as D, type OrganizationRole as O, type RefreshedTokens as R, type TokenTypeHint as T, type CboxIdConfig as a, type AuthorizationRequest as b, type AuthorizationPrompt as c, type CboxActiveOrganization as d, type CboxActor as e, type CboxOrganization as f, type ClaimSource as g, type DiscoveryDocument as h, type TokenResponse as i, actor as j, hasPermission as k, hasRole as l, isSupportSession as m, organization as o, permissions as p, roles as r, sessionId as s };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@cboxdk/id-js",
3
- "version": "0.15.1",
3
+ "version": "0.17.0",
4
4
  "description": "Turnkey Cbox ID client for JavaScript/TypeScript — OpenID Connect login (PKCE + id_token verification via JWKS), hosted profile-management redirect, machine tokens, UserInfo, RFC 7662 introspection, and webhook signature verification. Runs on Node, edge, and the browser, with a first-class Next.js adapter.",
5
5
  "type": "module",
6
6
  "license": "MIT",
@@ -37,6 +37,11 @@
37
37
  "types": "./dist/nextjs.d.ts",
38
38
  "import": "./dist/nextjs.js",
39
39
  "require": "./dist/nextjs.cjs"
40
+ },
41
+ "./server": {
42
+ "types": "./dist/server.d.ts",
43
+ "import": "./dist/server.js",
44
+ "require": "./dist/server.cjs"
40
45
  }
41
46
  },
42
47
  "files": [
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/errors.ts","../src/pkce.ts","../src/vault.ts","../src/webhook.ts","../src/discovery.ts","../src/issuer.ts","../src/client.ts"],"names":["key"],"mappings":"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","file":"chunk-3V6OKRWF.js","sourcesContent":["/**\n * Base class for every error this SDK throws, so callers can `catch (e) { if (e\n * instanceof CboxIdError) ... }` in one branch.\n */\nexport class CboxIdError extends Error {\n constructor(message: string) {\n super(message);\n this.name = new.target.name;\n }\n}\n\n/** The client is misconfigured (a required option is missing or empty). */\nexport class ConfigurationError extends CboxIdError {}\n\n/**\n * The login `state` did not match what was stored — the callback is forged or\n * stale. Treat as a fresh start, not an error to surface to the user.\n */\nexport class InvalidStateError extends CboxIdError {}\n\n/**\n * Login could not be completed: the provider returned an error, the callback was\n * missing a code, or a token / id_token failed verification.\n *\n * `error` carries the RFC 6749 §5.2 code the authorization server sent, when it sent one.\n * It used to be discarded at every back-channel boundary, leaving a single message string\n * for outcomes that need opposite responses: `invalid_grant` on a refresh means the\n * session is over and the person has to sign in again, while `temporarily_unavailable`\n * means try the same token in a moment. A caller reduced to matching on prose either\n * retries what can never succeed, or signs out somebody who did not need to be.\n */\nexport class AuthenticationError extends CboxIdError {\n constructor(\n message: string,\n /** RFC 6749 §5.2 error code, when the server sent a parseable one. */\n readonly error?: string,\n /** The server's `error_description`, verbatim. Not end-user copy. */\n readonly errorDescription?: string,\n /** HTTP status, for the cases where the body says nothing useful. */\n readonly status?: number,\n /**\n * Seconds to wait, off the `Retry-After` header — set only on a 429.\n *\n * The distinction it carries is the one a caller most needs and could least infer:\n * a 429 is the ONLY back-channel failure where the same request will succeed\n * unchanged if you simply wait. Every other one needs a different request, or a new\n * sign-in. Without this the SDK reported \"token refresh failed\" and a caller with a\n * retry loop hammered a limiter that was already telling it exactly how long to stop.\n */\n readonly retryAfter?: number,\n ) {\n super(message);\n }\n\n /** Whether waiting `retryAfter` seconds and repeating the same request is worth it. */\n get isRateLimited(): boolean {\n return this.status === 429;\n }\n}\n\n/**\n * Read an OAuth error out of a failed token-endpoint response.\n *\n * Best-effort by design: a 502 from a proxy is HTML, a captive portal is worse, and the\n * caller still needs an error rather than a parse exception. What it must never do is\n * invent a code — an absent or unparseable `error` stays undefined, so\n * `e.error === 'invalid_grant'` is true only because the server said so.\n */\nexport async function oauthError(response: Response, fallback: string): Promise<AuthenticationError> {\n const body = await response.text().catch(() => '');\n\n let code: string | undefined;\n let description: string | undefined;\n\n try {\n const parsed: unknown = JSON.parse(body);\n\n if (typeof parsed === 'object' && parsed !== null) {\n const { error, error_description: errorDescription } = parsed as Record<string, unknown>;\n code = typeof error === 'string' ? error : undefined;\n description = typeof errorDescription === 'string' ? errorDescription : undefined;\n }\n } catch {\n // Not JSON. The status and the truncated body below are all there is to report.\n }\n\n // THE BODY IS NEVER ECHOED. These calls carry `client_secret`, `code_verifier` and\n // refresh tokens in their REQUEST, and a debug proxy, a captive portal or an upstream\n // error page that reflects what it received puts those straight into a thrown message\n // — which production apps log. Only the server's own OAuth error code travels, and\n // failing that, the status alone.\n const detail = code ?? `HTTP ${response.status}`;\n\n // `Retry-After` is seconds here — Laravel's throttler writes the integer form. The\n // HTTP-date form is legal too and is deliberately NOT parsed: guessing at a clock\n // skew is worse than saying nothing, and `status === 429` still tells the caller to\n // back off.\n const retryAfterHeader = response.headers.get('retry-after');\n const retryAfter = retryAfterHeader !== null && /^\\d+$/.test(retryAfterHeader.trim())\n ? Number(retryAfterHeader.trim())\n : undefined;\n\n return new AuthenticationError(`${fallback}: ${detail}`, code, description, response.status, retryAfter);\n}\n\n/**\n * The Frontend API refused, or could not be reached.\n *\n * Carries a `code` because the four ways this goes wrong need four different responses\n * from the caller, and telling them apart from a message string is the kind of thing\n * that works until somebody rewords the message:\n *\n * - `origin_not_allowed` — the overwhelmingly likely cause of a refusal, and a\n * configuration problem the developer fixes once in the console.\n * - `rate_limited` — back off; `retryAfter` says for how long, when the server said.\n * - `unavailable` — the network, or a 5xx. Transient by assumption; already retried.\n * - `malformed` — a 200 whose body is not the document we expect, which means something\n * between the page and us is rewriting responses (a proxy, an extension, a captive\n * portal). Worth distinguishing, because retrying it never helps.\n */\nexport class FrontendApiError extends CboxIdError {\n constructor(\n message: string,\n readonly code: 'origin_not_allowed' | 'rate_limited' | 'unavailable' | 'malformed',\n readonly status?: number,\n readonly retryAfter?: number,\n ) {\n super(message);\n }\n}\n","/**\n * PKCE (RFC 7636) and the random values the login flow needs, built on Web Crypto\n * (`globalThis.crypto`) so the same code runs on Node, edge runtimes and browsers.\n */\n\nfunction base64url(bytes: Uint8Array): string {\n let binary = '';\n for (const byte of bytes) {\n binary += String.fromCharCode(byte);\n }\n return btoa(binary).replace(/\\+/g, '-').replace(/\\//g, '_').replace(/=+$/, '');\n}\n\n/** A URL-safe random token of `bytes` bytes (default 32), for state and nonce. */\nexport function randomToken(bytes = 32): string {\n return base64url(crypto.getRandomValues(new Uint8Array(bytes)));\n}\n\n/** A high-entropy PKCE code verifier. */\nexport function createVerifier(): string {\n return randomToken(32);\n}\n\n/** The S256 code challenge for a verifier. */\nexport async function challenge(verifier: string): Promise<string> {\n const digest = await crypto.subtle.digest('SHA-256', new TextEncoder().encode(verifier));\n return base64url(new Uint8Array(digest));\n}\n","import { AuthenticationError } from './errors.js';\n\n/** A stored vault secret's metadata (never its plaintext). */\nexport interface VaultSecretRef {\n id: string;\n name: string;\n provider: string;\n ownerType: string | null;\n ownerId: string | null;\n expiresAt: string | null;\n revoked: boolean;\n}\n\n/** A brokered credential — the plaintext, for immediate use. */\nexport interface VaultLease {\n secretId: string;\n provider: string;\n secret: string;\n expiresAt: string;\n}\n\nexport interface StoreSecretInput {\n name: string;\n provider: string;\n secret: string;\n ownerType?: 'organization' | 'user';\n ownerId?: string;\n expiresAt?: string;\n}\n\n/**\n * Client for a Cbox ID instance's Token Vault API. Bind it to an access token\n * (obtain one with {@link CboxIdClient.machineToken}, scoped `vault.manage` for\n * provisioning or `vault.lease` for redeeming). All calls are server-to-server.\n */\nexport class VaultClient {\n private readonly base: string;\n\n constructor(\n issuer: string,\n private readonly token: string,\n private readonly timeoutMs = 10_000,\n ) {\n this.base = `${issuer.replace(/\\/$/, '')}/api/v1/vault`;\n }\n\n /** Ingest a downstream credential, sealed at rest (scope `vault.manage`). */\n store(input: StoreSecretInput): Promise<VaultSecretRef> {\n return this.json<VaultSecretRef>('POST', '/secrets', {\n name: input.name,\n provider: input.provider,\n secret: input.secret,\n owner_type: input.ownerType,\n owner_id: input.ownerId,\n expires_at: input.expiresAt,\n });\n }\n\n /** Rotate a secret's value, keeping its id and grants (scope `vault.manage`). */\n rotate(secretId: string, secret: string): Promise<VaultSecretRef> {\n return this.json<VaultSecretRef>('POST', `/secrets/${encodeURIComponent(secretId)}/rotate`, { secret });\n }\n\n /** Revoke a secret permanently (scope `vault.manage`). */\n async revoke(secretId: string): Promise<void> {\n await this.request('DELETE', `/secrets/${encodeURIComponent(secretId)}`);\n }\n\n /** Authorize an agent client to lease a secret (scope `vault.manage`). */\n grant(\n secretId: string,\n clientId: string,\n maxTtlSeconds?: number,\n ): Promise<{ secretId: string; clientId: string; maxTtlSeconds: number | null }> {\n return this.json('POST', `/secrets/${encodeURIComponent(secretId)}/grants`, {\n client_id: clientId,\n max_ttl_seconds: maxTtlSeconds,\n }).then((raw) => {\n const r = raw as { secret_id: string; client_id: string; max_ttl_seconds: number | null };\n return { secretId: r.secret_id, clientId: r.client_id, maxTtlSeconds: r.max_ttl_seconds };\n });\n }\n\n /** Revoke an agent's authorization (scope `vault.manage`). */\n async revokeGrant(secretId: string, clientId: string): Promise<void> {\n await this.request(\n 'DELETE',\n `/secrets/${encodeURIComponent(secretId)}/grants/${encodeURIComponent(clientId)}`,\n );\n }\n\n /**\n * Redeem a leased credential for immediate use (scope `vault.lease`). The caller\n * is identified by the token's client; a lease with no live grant is refused.\n */\n lease(secretId: string, purpose: string): Promise<VaultLease> {\n return this.json('POST', `/secrets/${encodeURIComponent(secretId)}/lease`, { purpose }).then((raw) => {\n const r = raw as { secret_id: string; provider: string; secret: string; expires_at: string };\n return { secretId: r.secret_id, provider: r.provider, secret: r.secret, expiresAt: r.expires_at };\n });\n }\n\n private async json<T>(method: string, path: string, body: Record<string, unknown>): Promise<T> {\n const response = await this.request(method, path, body);\n return (await response.json()) as T;\n }\n\n private async request(method: string, path: string, body?: Record<string, unknown>): Promise<Response> {\n const controller = new AbortController();\n const timer = setTimeout(() => controller.abort(), this.timeoutMs);\n try {\n const init: RequestInit = {\n method,\n headers: {\n authorization: `Bearer ${this.token}`,\n ...(body ? { 'content-type': 'application/json' } : {}),\n },\n signal: controller.signal,\n };\n if (body) {\n init.body = JSON.stringify(body);\n }\n const response = await fetch(`${this.base}${path}`, init);\n if (!response.ok) {\n throw new AuthenticationError(`Vault ${method} ${path} failed with status ${response.status}.`);\n }\n return response;\n } finally {\n clearTimeout(timer);\n }\n }\n}\n","/**\n * Verify a Cbox ID webhook / inline-action signature. The header is\n * `X-Cbox-Signature: t={unix},v1={hex hmac}` — an HMAC-SHA256 over\n * `\"{timestamp}.{raw body}\"`, valid within a freshness window. Built on Web Crypto\n * so it runs on Node, edge and the browser.\n */\n\n/** Constant-time compare of two hex strings. */\nfunction timingSafeEqual(a: string, b: string): boolean {\n if (a.length !== b.length) {\n return false;\n }\n let mismatch = 0;\n for (let i = 0; i < a.length; i++) {\n mismatch |= a.charCodeAt(i) ^ b.charCodeAt(i);\n }\n return mismatch === 0;\n}\n\nfunction toHex(bytes: ArrayBuffer): string {\n return Array.from(new Uint8Array(bytes))\n .map((b) => b.toString(16).padStart(2, '0'))\n .join('');\n}\n\nexport interface VerifyWebhookOptions {\n /** The RAW request body — the exact bytes received, not a re-encoded copy. */\n payload: string;\n /** The value of the `X-Cbox-Signature` header. */\n signatureHeader: string | null | undefined;\n /** The signing secret issued when the webhook/action endpoint was registered. */\n secret: string;\n /** Freshness window in seconds. Defaults to 300 (5 minutes). */\n toleranceSeconds?: number;\n /** Injectable clock (unix seconds), for tests. Defaults to `Date.now()`. */\n now?: number;\n}\n\n/** Returns `true` only when the signature is present, fresh and valid. Never throws. */\nexport async function verifyWebhook(options: VerifyWebhookOptions): Promise<boolean> {\n const { payload, signatureHeader, secret } = options;\n const toleranceSeconds = options.toleranceSeconds ?? 300;\n const now = options.now ?? Math.floor(Date.now() / 1000);\n\n if (!signatureHeader) {\n return false;\n }\n\n const parts: Record<string, string> = {};\n for (const segment of signatureHeader.split(',')) {\n const [key, value] = segment.trim().split('=', 2);\n if (key) {\n parts[key] = value ?? '';\n }\n }\n\n const timestamp = parts['t'] ?? '';\n const signature = parts['v1'] ?? '';\n\n if (timestamp === '' || signature === '' || !/^\\d+$/.test(timestamp)) {\n return false;\n }\n\n if (Math.abs(now - Number(timestamp)) > toleranceSeconds) {\n return false;\n }\n\n const key = await crypto.subtle.importKey(\n 'raw',\n new TextEncoder().encode(secret),\n { name: 'HMAC', hash: 'SHA-256' },\n false,\n ['sign'],\n );\n const expected = toHex(\n await crypto.subtle.sign('HMAC', key, new TextEncoder().encode(`${timestamp}.${payload}`)),\n );\n\n return timingSafeEqual(expected, signature);\n}\n","import { AuthenticationError, ConfigurationError } from './errors.js';\nimport type { DiscoveryDocument } from './types.js';\n\n/**\n * Fetches and caches an instance's OIDC discovery document. One instance of this\n * lives per {@link CboxIdClient}; the document is refetched only after the TTL.\n */\nexport class Discovery {\n private cached: { doc: DiscoveryDocument; expiresAt: number } | null = null;\n\n constructor(\n private readonly issuer: string,\n private readonly timeoutMs: number,\n private readonly cacheTtlMs: number,\n private readonly now: () => number = Date.now,\n ) {}\n\n async document(): Promise<DiscoveryDocument> {\n if (this.cached && this.cached.expiresAt > this.now()) {\n return this.cached.doc;\n }\n\n const url = `${trimSlash(this.issuer)}/.well-known/openid-configuration`;\n const controller = new AbortController();\n const timer = setTimeout(() => controller.abort(), this.timeoutMs);\n\n let doc: DiscoveryDocument;\n try {\n const response = await fetch(url, { signal: controller.signal });\n if (!response.ok) {\n throw new AuthenticationError(`Discovery request failed with status ${response.status}.`);\n }\n doc = (await response.json()) as DiscoveryDocument;\n } catch (error) {\n if (error instanceof AuthenticationError) {\n throw error;\n }\n throw new AuthenticationError(`Discovery request failed: ${String(error)}`);\n } finally {\n clearTimeout(timer);\n }\n\n if (typeof doc.issuer !== 'string' || doc.issuer === '') {\n throw new AuthenticationError('The discovery document was missing an issuer.');\n }\n\n // RFC 8414 §3.3: the `issuer` in the document MUST match the one it was fetched for.\n // Without this the SDK sends credentials to whatever endpoints the document names and\n // verifies tokens against whatever JWKS it points at, while the caller still believes\n // it is talking to the issuer it configured — so one tenant's host answering with\n // another tenant's document silently redirects the whole flow.\n if (trimSlash(doc.issuer) !== trimSlash(this.issuer)) {\n throw new AuthenticationError(\n `The discovery document is for a different issuer (${doc.issuer}).`,\n );\n }\n\n this.cached = { doc, expiresAt: this.now() + this.cacheTtlMs };\n return doc;\n }\n\n /** A required endpoint from the discovery document. */\n async endpoint(name: keyof DiscoveryDocument): Promise<string> {\n const value = (await this.document())[name];\n if (typeof value !== 'string' || value === '') {\n throw new ConfigurationError(`The instance does not advertise a ${name}.`);\n }\n return value;\n }\n\n /** An optional endpoint, or null when the instance advertises none. */\n async optionalEndpoint(name: keyof DiscoveryDocument): Promise<string | null> {\n const value = (await this.document())[name];\n return typeof value === 'string' && value !== '' ? value : null;\n }\n}\n\n/** Compare issuers without letting a trailing slash decide identity. */\nfunction trimSlash(value: string): string {\n return value.replace(/\\/+$/, '');\n}\n","import { ConfigurationError } from './errors.js';\n\n/**\n * An issuer must be HTTPS.\n *\n * Everything this SDK does with it carries a credential: the authorization code, the PKCE\n * verifier, the client secret, the refresh token. Over `http://` a network attacker reads\n * all of them — and, worse, replaces the discovery document and JWKS, at which point a\n * forged id_token verifies cleanly and the whole verification chain proves nothing.\n *\n * Loopback is allowed because a native app's own callback listener is loopback by\n * definition (RFC 8252) and a dev instance runs there.\n */\nexport function assertSecureIssuer(issuer: string): void {\n let url: URL;\n\n try {\n url = new URL(issuer);\n } catch {\n throw new ConfigurationError('Cbox ID config `issuer` is not a valid URL.');\n }\n\n if (url.protocol === 'https:') {\n return;\n }\n\n const loopback = url.hostname === 'localhost' || url.hostname === '127.0.0.1' || url.hostname === '[::1]' || url.hostname === '::1';\n\n if (url.protocol === 'http:' && loopback) {\n return;\n }\n\n throw new ConfigurationError(\n `Cbox ID config \\`issuer\\` must be https (got ${url.protocol}//${url.hostname}).`,\n );\n}\n","import { createRemoteJWKSet, jwtVerify, type JWTPayload } from 'jose';\nimport { Discovery } from './discovery.js';\nimport { assertSecureIssuer } from './issuer.js';\nimport { AuthenticationError, ConfigurationError, InvalidStateError, oauthError } from './errors.js';\nimport { challenge, createVerifier, randomToken } from './pkce.js';\nimport type {\n AuthorizationRequest,\n CboxIdConfig,\n CboxOrganization,\n CboxUser,\n RefreshedTokens,\n TokenResponse,\n TokenTypeHint,\n} from './types.js';\nimport { VaultClient } from './vault.js';\nimport { verifyWebhook, type VerifyWebhookOptions } from './webhook.js';\n\ntype JwksResolver = ReturnType<typeof createRemoteJWKSet>;\n\n/** Query parameters as they arrive on your callback route. */\nexport interface CallbackParams {\n code?: string | null;\n state?: string | null;\n error?: string | null;\n error_description?: string | null;\n}\n\n/** The values you persisted from {@link CboxIdClient.createAuthorizationRequest}. */\nexport interface StoredAuthState {\n state: string;\n codeVerifier: string;\n nonce: string;\n /** The `maxAge` this login demanded, if any. See {@link AuthorizationRequest.maxAge}. */\n maxAge?: number;\n /**\n * The scopes THIS authorization asked for, when you overrode the configured set.\n *\n * Read so `authenticate()` can judge the response against what was requested rather\n * than against the config: a login that asked for `openid` and came back without an\n * id_token is a protocol violation, and one that never asked cannot be held to it.\n * Omitted, the configured scopes are assumed — which is what a caller who did not\n * override them actually sent.\n */\n scopes?: string[];\n}\n\n/**\n * Turnkey Cbox ID client for JavaScript/TypeScript. It speaks standard OpenID\n * Connect against a Cbox ID instance — so integrating is a redirect and a callback,\n * not a rewrite — and adds the conveniences a hosted-identity product needs: a\n * redirect to the instance's hosted profile page, and back-channel helpers (machine\n * tokens, userinfo, introspection, webhook verification).\n *\n * Login is hardened by default: PKCE (S256), a CSRF state check, a nonce, and full\n * id_token signature + issuer + audience verification against the instance's JWKS\n * (via `jose`).\n *\n * The class is framework-agnostic: {@link createAuthorizationRequest} hands you the\n * `state`, `codeVerifier` and `nonce` to persist however you like, and\n * {@link authenticate} takes them back. For Next.js, the `@cboxdk/id-js/nextjs`\n * entry wires this to cookies for you.\n */\nexport class CboxIdClient {\n private readonly discovery: Discovery;\n private readonly jwksByUri = new Map<string, JwksResolver>();\n\n constructor(private readonly config: CboxIdConfig) {\n if (!config.issuer) {\n throw new ConfigurationError('Cbox ID config `issuer` is required.');\n }\n if (!config.clientId) {\n throw new ConfigurationError('Cbox ID config `clientId` is required.');\n }\n if (!config.redirectUri) {\n throw new ConfigurationError('Cbox ID config `redirectUri` is required.');\n }\n assertSecureIssuer(config.issuer);\n this.discovery = new Discovery(\n config.issuer,\n config.timeoutMs ?? 10_000,\n config.cacheTtlMs ?? 3_600_000,\n );\n }\n\n /**\n * Begin login. Returns the authorize URL plus the `state`, `codeVerifier` and\n * `nonce` — persist those (signed, httpOnly cookies are ideal) and hand them back\n * to {@link authenticate} on the callback.\n */\n async createAuthorizationRequest(options: {\n scopes?: string[];\n redirectUri?: string;\n state?: string;\n prompt?: string;\n loginHint?: string;\n maxAge?: number;\n } = {}): Promise<AuthorizationRequest> {\n const codeVerifier = createVerifier();\n const state = options.state ?? randomToken(16);\n const nonce = randomToken(16);\n\n const params = new URLSearchParams({\n response_type: 'code',\n client_id: this.config.clientId,\n redirect_uri: options.redirectUri ?? this.config.redirectUri,\n scope: (options.scopes ?? this.scopes()).join(' '),\n state,\n nonce,\n code_challenge: await challenge(codeVerifier),\n code_challenge_method: 'S256',\n });\n if (options.prompt) {\n params.set('prompt', options.prompt);\n }\n if (options.loginHint) {\n params.set('login_hint', options.loginHint);\n }\n if (typeof options.maxAge === 'number') {\n params.set('max_age', String(options.maxAge));\n }\n\n const endpoint = await this.discovery.endpoint('authorization_endpoint');\n return {\n url: `${endpoint}?${params.toString()}`,\n state,\n codeVerifier,\n nonce,\n // Carried through so authenticate() can hold the instance to it. Only present\n // when requested (exactOptionalPropertyTypes).\n ...(typeof options.maxAge === 'number' ? { maxAge: options.maxAge } : {}),\n };\n }\n\n /**\n * Complete login on your callback route: verify state, exchange the code with the\n * PKCE verifier, verify the id_token, and return the authenticated user.\n *\n * @throws InvalidStateError when state does not match (forged/stale request)\n * @throws AuthenticationError on any other failure\n */\n async authenticate(input: {\n params: CallbackParams;\n stored: StoredAuthState;\n redirectUri?: string;\n }): Promise<CboxUser> {\n const { params, stored } = input;\n\n if (!params.state || !stored.state || !timingSafeEqualString(params.state, stored.state)) {\n throw new InvalidStateError('The login state did not match — the request may be forged or stale.');\n }\n\n if (params.error) {\n throw new AuthenticationError(\n `Cbox ID returned an error: ${params.error}${params.error_description ? ` (${params.error_description})` : ''}`,\n );\n }\n\n if (!params.code) {\n throw new AuthenticationError('The callback was missing an authorization code.');\n }\n\n const tokens = await this.exchange(params.code, stored.codeVerifier, input.redirectUri);\n\n if (!tokens.access_token) {\n throw new AuthenticationError('No access token was returned.');\n }\n\n let verified: Record<string, unknown> = {};\n\n if (tokens.id_token) {\n verified = await this.verifyIdToken(tokens.id_token, stored.nonce, stored.maxAge);\n } else if ((stored.scopes ?? this.scopes()).includes('openid')) {\n // AN `openid` REQUEST WITHOUT AN ID_TOKEN IS A PROTOCOL VIOLATION, and refusing it\n // is the difference between an authenticated login and a bearer token. Without this\n // the identity below came from UserInfo alone — a bearer-authenticated endpoint\n // whose response nothing signed — and the `nonce` pulled from storage was never used.\n //\n // Asked of the SCOPES REQUESTED, not of the response: a caller who never asked for\n // `openid` is running an OAuth flow and is not held to an OIDC rule.\n throw new AuthenticationError(\n 'An openid login returned no id_token, so the identity could not be verified.',\n );\n } else if (typeof stored.maxAge === 'number') {\n // No id_token means no auth_time, and therefore no evidence the demanded\n // re-authentication happened. Accepting that silently is the whole defect.\n throw new AuthenticationError(\n 'A max_age was requested but no id_token was returned, so the authentication age could not be verified.',\n );\n }\n\n const profile = await this.userinfo(tokens.access_token);\n\n // OIDC Core §5.3.2: the UserInfo `sub` MUST match the id_token's, and when it does\n // not the response MUST NOT be used. UserInfo is fetched with a bearer token and its\n // body carries no signature, so without this an IdP — or anything able to answer as\n // one — hands back `{\"sub\":\"somebody-else\"}` and the SDK returns it as the identity.\n const verifiedSub = verified['sub'];\n const profileSub = profile['sub'];\n\n if (typeof verifiedSub === 'string' && typeof profileSub === 'string' && !timingSafeEqualString(verifiedSub, profileSub)) {\n throw new AuthenticationError('The UserInfo subject does not match the verified id_token.');\n }\n\n // ENRICHES, NEVER REPLACES. UserInfo fills in what a minimal id_token omits (email,\n // name, org) and the verified claims go back on top, so the merge cannot move `sub`,\n // `iss`, `aud`, `nonce` or anything else the signature covered. The spread used to run\n // the other way round.\n const claims: Record<string, unknown> = { ...profile, ...verified };\n\n const sub = claims['sub'];\n if (typeof sub !== 'string' || sub === '') {\n throw new AuthenticationError('The verified token carried no subject.');\n }\n\n const organizations = parseOrganizations(claims['organizations']);\n\n return {\n id: sub,\n email: typeof claims['email'] === 'string' ? claims['email'] : null,\n name: typeof claims['name'] === 'string' ? claims['name'] : null,\n organizationId: typeof claims['org'] === 'string' ? claims['org'] : null,\n // Only present when the instance emitted the claim (exactOptionalPropertyTypes).\n ...(organizations ? { organizations } : {}),\n claims,\n accessToken: tokens.access_token,\n refreshToken: tokens.refresh_token ?? null,\n idToken: tokens.id_token ?? null,\n expiresIn: typeof tokens.expires_in === 'number' ? tokens.expires_in : 0,\n };\n }\n\n /**\n * Exchange a refresh token for a fresh access token (OAuth 2.0 `refresh_token`\n * grant). Cbox ID rotates refresh tokens and detects reuse, so ALWAYS persist the\n * returned `refreshToken` and discard the one you passed — presenting a rotated\n * token again revokes the entire token family.\n *\n * @throws AuthenticationError when the refresh token is invalid, expired, or already rotated.\n */\n async refresh(refreshToken: string): Promise<RefreshedTokens> {\n const body = new URLSearchParams({\n grant_type: 'refresh_token',\n client_id: this.config.clientId,\n refresh_token: refreshToken,\n });\n if (this.config.clientSecret) {\n body.set('client_secret', this.config.clientSecret);\n }\n\n const response = await this.post(await this.discovery.endpoint('token_endpoint'), body);\n if (!response.ok) {\n // The most consequential of these: `invalid_grant` means the refresh token is\n // spent, revoked or replayed and the person must sign in again, while a 5xx or\n // `temporarily_unavailable` means the same token is still good in a moment. One\n // message string for both is what makes callers guess.\n throw await oauthError(response, 'Token refresh failed');\n }\n\n const tokens = (await response.json()) as TokenResponse;\n if (!tokens.access_token) {\n throw new AuthenticationError('The refresh response carried no access token.');\n }\n\n // VERIFIED BEFORE IT IS HANDED BACK. A refresh response carries a fresh id_token, and\n // this returned it unchecked — so an application that refreshes its session claims\n // from `refresh().idToken` accepted a forged, expired, wrong-audience or wrong-issuer\n // token, having verified only the one it got at login. The nonce is not re-checked:\n // RFC 6749 has no nonce on this leg, and OIDC Core §12.2 says an id_token from a\n // refresh need not carry one.\n if (tokens.id_token) {\n await this.verifyIdToken(tokens.id_token, '');\n }\n\n return {\n accessToken: tokens.access_token,\n // Keep the presented token when the server does not rotate (OAuth 2.0 §6);\n // callers persist this value, so it must never come back null.\n refreshToken: tokens.refresh_token ?? refreshToken,\n idToken: tokens.id_token ?? null,\n expiresIn: typeof tokens.expires_in === 'number' ? tokens.expires_in : 0,\n scope: typeof tokens.scope === 'string' ? tokens.scope : null,\n };\n }\n\n /**\n * The URL of the instance's hosted account/profile page (self-service password,\n * MFA, passkeys, sessions). A signed-in user is authenticated there by their Cbox\n * ID session; `returnTo` is passed so the page can link back to your app.\n */\n profileUrl(returnTo?: string): string {\n const base = `${this.config.issuer.replace(/\\/$/, '')}${this.accountPath()}`;\n return returnTo ? `${base}?${new URLSearchParams({ return_to: returnTo }).toString()}` : base;\n }\n\n /**\n * The RP-initiated logout URL, or null when the instance advertises none.\n *\n * `client_id` is always sent, even without a `returnTo`: the OP validates\n * `post_logout_redirect_uri` against the registered allow-list of THAT client\n * (OIDC RP-Initiated Logout 1.0 §2). With no way to name the RP the OP cannot\n * check the list, so it silently drops the return URL and strands the user on a\n * bare \"you are signed out\" page. `idTokenHint` — the user's `id_token`, if you\n * still hold it — is the spec's other way to identify the RP, and additionally\n * tells the OP which subject is logging out.\n *\n * PASS THE HINT IF YOU WANT \"SIGN OUT EVERYWHERE\". Cbox ID revokes every session\n * the person holds only when a hint it can VERIFY names the subject holding the\n * browser; with no hint it signs this browser out and leaves their other devices\n * alone. That is deliberate: the endpoint is unauthenticated and reached by a\n * redirect, so a request carrying no proof of who it concerns could otherwise be\n * forged into ending anyone's sessions everywhere. See laravel-id UPGRADING.md\n * for 1.8.0.\n */\n async logoutUrl(returnTo?: string, idTokenHint?: string): Promise<string | null> {\n const endpoint = await this.discovery.optionalEndpoint('end_session_endpoint');\n if (!endpoint) {\n return null;\n }\n const params = new URLSearchParams({ client_id: this.config.clientId });\n if (returnTo) {\n params.set('post_logout_redirect_uri', returnTo);\n }\n if (idTokenHint) {\n params.set('id_token_hint', idTokenHint);\n }\n return `${endpoint}?${params.toString()}`;\n }\n\n /**\n * A machine (client-credentials) access token for calling Cbox ID APIs as your\n * app, not on a user's behalf. Requires a client secret.\n */\n async machineToken(options: { scopes?: string[]; resource?: string } = {}): Promise<string> {\n const body = new URLSearchParams({\n grant_type: 'client_credentials',\n client_id: this.config.clientId,\n client_secret: this.requireSecret(),\n });\n if (options.scopes && options.scopes.length > 0) {\n body.set('scope', options.scopes.join(' '));\n }\n if (options.resource) {\n body.set('resource', options.resource);\n }\n\n const response = await this.post(await this.discovery.endpoint('token_endpoint'), body);\n if (!response.ok) {\n throw await oauthError(response, 'Machine token request failed');\n }\n const json = (await response.json()) as { access_token?: unknown };\n if (typeof json.access_token !== 'string') {\n throw new AuthenticationError('The token response had no access_token.');\n }\n return json.access_token;\n }\n\n /** The OIDC userinfo claims for an access token. */\n async userinfo(accessToken: string): Promise<Record<string, unknown>> {\n const endpoint = await this.discovery.optionalEndpoint('userinfo_endpoint');\n if (!endpoint) {\n return {};\n }\n const response = await this.fetchWithTimeout(endpoint, {\n headers: { authorization: `Bearer ${accessToken}` },\n });\n if (!response.ok) {\n throw await oauthError(response, 'Userinfo request failed');\n }\n return (await response.json()) as Record<string, unknown>;\n }\n\n /**\n * RFC 7662 token introspection (confidential-client auth). Returns the raw\n * response; `active` tells you if the token is currently valid. Requires a secret.\n */\n async introspect(token: string): Promise<Record<string, unknown>> {\n const endpoint = await this.discovery.endpoint('introspection_endpoint');\n const basic = btoa(`${this.config.clientId}:${this.requireSecret()}`);\n const response = await this.post(\n endpoint,\n new URLSearchParams({ token }),\n { authorization: `Basic ${basic}` },\n );\n if (!response.ok) {\n throw await oauthError(response, 'Introspection request failed');\n }\n return (await response.json()) as Record<string, unknown>;\n }\n\n /**\n * RFC 7009 token revocation. Revokes an access or refresh token; revoking a refresh\n * token drops the whole token family, so this is what a real \"sign out everywhere\" does.\n *\n * **PUBLIC CLIENTS TOO.** This demanded a secret and threw `ConfigurationError` without\n * one — so the clients that most need it were the ones that could not call it. A PKCE\n * browser or native app authenticates with `none`, holds no secret, and is exactly the\n * case where a refresh token sits in storage on a device somebody has just signed out\n * of. Cbox ID's revocation endpoint accepts a public client, and its discovery document\n * advertises `none` among the revocation auth methods; RFC 7009 §2.1 scopes every\n * revocation to the calling client, so the only capability here is \"destroy a token you\n * are already holding\". The SDK was the half saying no.\n *\n * A confidential client still authenticates with Basic; a public one names itself in the\n * body, the same shape {@link exchange} already uses for the token endpoint.\n *\n * Per RFC 7009 the server answers 200 for an unknown or already-revoked token, so\n * success means \"this token is not valid any more\", not \"it existed\".\n *\n * @param tokenTypeHint which store to search first — only a hint, never required.\n */\n async revoke(token: string, tokenTypeHint?: TokenTypeHint): Promise<void> {\n const endpoint = await this.discovery.endpoint('revocation_endpoint');\n const body = new URLSearchParams({ token, client_id: this.config.clientId });\n if (tokenTypeHint) {\n body.set('token_type_hint', tokenTypeHint);\n }\n\n const headers: Record<string, string> = {};\n if (this.config.clientSecret) {\n headers.authorization = `Basic ${btoa(`${this.config.clientId}:${this.config.clientSecret}`)}`;\n }\n\n const response = await this.post(endpoint, body, headers);\n if (!response.ok) {\n throw await oauthError(response, 'Revocation request failed');\n }\n }\n\n /** Verify a Cbox ID webhook / inline-action signature. See {@link verifyWebhook}. */\n verifyWebhook(options: VerifyWebhookOptions): Promise<boolean> {\n return verifyWebhook(options);\n }\n\n /**\n * A Token Vault client bound to an access token. Obtain the token with\n * {@link machineToken} (scope `vault.manage` to provision/grant, `vault.lease` to\n * redeem), then call `store` / `grant` / `lease` etc.\n */\n vault(accessToken: string): VaultClient {\n return new VaultClient(this.config.issuer, accessToken, this.config.timeoutMs ?? 10_000);\n }\n\n private async exchange(code: string, verifier: string, redirectUri?: string): Promise<TokenResponse> {\n const body = new URLSearchParams({\n grant_type: 'authorization_code',\n code,\n redirect_uri: redirectUri ?? this.config.redirectUri,\n client_id: this.config.clientId,\n code_verifier: verifier,\n });\n if (this.config.clientSecret) {\n body.set('client_secret', this.config.clientSecret);\n }\n\n const response = await this.post(await this.discovery.endpoint('token_endpoint'), body);\n if (!response.ok) {\n throw await oauthError(response, 'Token exchange failed');\n }\n return (await response.json()) as TokenResponse;\n }\n\n private async verifyIdToken(\n idToken: string,\n // Empty skips the nonce comparison below, which is what a refresh leg needs: RFC 6749\n // has no nonce there and OIDC Core §12.2 says the id_token from a refresh need not\n // carry one. Signature, issuer, audience and expiry are checked either way.\n nonce: string,\n maxAge?: number,\n ): Promise<Record<string, unknown>> {\n const jwksUri = await this.discovery.endpoint('jwks_uri');\n let resolver = this.jwksByUri.get(jwksUri);\n if (!resolver) {\n resolver = createRemoteJWKSet(new URL(jwksUri));\n this.jwksByUri.set(jwksUri, resolver);\n }\n\n let payload: JWTPayload;\n try {\n ({ payload } = await jwtVerify(idToken, resolver, {\n issuer: this.config.issuer,\n audience: this.config.clientId,\n // Pin the accepted signature algorithms explicitly. `jose` already refuses\n // `alg: none` and key-type confusion, so this is belt-and-braces — but it\n // states the contract in code rather than relying on a library default.\n algorithms: ['RS256', 'ES256'],\n }));\n } catch (error) {\n throw new AuthenticationError(`The id_token could not be verified: ${String(error)}`);\n }\n\n if (nonce && payload['nonce'] !== nonce) {\n throw new AuthenticationError('The id_token nonce did not match — possible replay.');\n }\n\n // OIDC Core §3.1.3.7 step 12: when max_age was requested, `auth_time` is REQUIRED\n // and the relying party MUST check it. `max_age` is the control you reach for\n // before a payment or an admin grant, and the whole point is that the person\n // authenticated JUST NOW — so a login({maxAge}) whose result is never checked is a\n // step-up in name only: a day-old session comes back carrying its original\n // auth_time and nothing anywhere says so.\n if (typeof maxAge === 'number') {\n const authTime = payload['auth_time'];\n\n if (typeof authTime !== 'number') {\n throw new AuthenticationError(\n 'A max_age was requested but the id_token carried no auth_time, so the authentication age could not be verified.',\n );\n }\n\n const tolerance = this.config.authTimeToleranceSeconds ?? 60;\n const age = Math.floor(Date.now() / 1000) - authTime;\n\n if (age > maxAge + tolerance) {\n throw new AuthenticationError(\n `The authentication is ${age}s old but max_age required ${maxAge}s — the user did not re-authenticate.`,\n );\n }\n }\n\n return payload as Record<string, unknown>;\n }\n\n private scopes(): string[] {\n const scopes = this.config.scopes;\n return scopes && scopes.length > 0 ? scopes : ['openid', 'profile', 'email'];\n }\n\n private accountPath(): string {\n const path = this.config.accountPath;\n // `/account`, not `/settings`. The latter is the organization-admin page: it\n // redirects a non-admin to `/account` and drops `return_to` on the way, so a member\n // following this link arrives at the right screen having lost where they came from.\n return path && path !== '' ? `/${path.replace(/^\\//, '')}` : '/account';\n }\n\n private requireSecret(): string {\n if (!this.config.clientSecret) {\n throw new ConfigurationError('This call requires a `clientSecret`, but none is configured.');\n }\n return this.config.clientSecret;\n }\n\n private post(url: string, body: URLSearchParams, headers: Record<string, string> = {}): Promise<Response> {\n return this.fetchWithTimeout(url, {\n method: 'POST',\n headers: { 'content-type': 'application/x-www-form-urlencoded', ...headers },\n body,\n });\n }\n\n private async fetchWithTimeout(url: string, init: RequestInit): Promise<Response> {\n const controller = new AbortController();\n const timer = setTimeout(() => controller.abort(), this.config.timeoutMs ?? 10_000);\n try {\n return await fetch(url, { ...init, signal: controller.signal });\n } finally {\n clearTimeout(timer);\n }\n }\n}\n\n/** Constant-time string compare, so state validation doesn't leak via timing. */\nfunction timingSafeEqualString(a: string, b: string): boolean {\n if (a.length !== b.length) {\n return false;\n }\n let mismatch = 0;\n for (let i = 0; i < a.length; i++) {\n mismatch |= a.charCodeAt(i) ^ b.charCodeAt(i);\n }\n return mismatch === 0;\n}\n\n/**\n * Parse an `organizations` claim into typed orgs, ignoring anything malformed. The\n * claim is optional and instance-specific; absent or non-array → undefined, so\n * callers can tell \"no claim\" from \"empty\".\n */\nfunction parseOrganizations(claim: unknown): CboxOrganization[] | undefined {\n if (!Array.isArray(claim)) {\n return undefined;\n }\n const orgs: CboxOrganization[] = [];\n for (const entry of claim) {\n if (typeof entry !== 'object' || entry === null) {\n continue;\n }\n const record = entry as Record<string, unknown>;\n const id = record['id'];\n const name = record['name'];\n if (typeof id === 'string' && id !== '' && typeof name === 'string' && name !== '') {\n orgs.push({ id, name, role: typeof record['role'] === 'string' ? record['role'] : null });\n }\n }\n return orgs;\n}\n"]}