@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.
- package/CHANGELOG.md +213 -0
- package/README.md +51 -3
- package/RELEASE-CANDIDATE.md +11 -0
- package/dist/agent.cjs +613 -0
- package/dist/agent.cjs.map +1 -0
- package/dist/agent.d.cts +400 -0
- package/dist/agent.d.ts +400 -0
- package/dist/agent.js +527 -0
- package/dist/agent.js.map +1 -0
- package/dist/api-keys-BE3R3q_A.d.ts +105 -0
- package/dist/api-keys-C8-Q4eFA.d.cts +105 -0
- package/dist/chunk-EVZ6RB3K.js +98 -0
- package/dist/chunk-EVZ6RB3K.js.map +1 -0
- package/dist/{chunk-YGLMLIKL.js → chunk-T5LCQOLS.js} +4 -22
- package/dist/chunk-T5LCQOLS.js.map +1 -0
- package/dist/chunk-VGQASHTI.js +22 -0
- package/dist/chunk-VGQASHTI.js.map +1 -0
- package/dist/decisions-C84Fzah4.d.ts +23 -0
- package/dist/decisions-DNd9UXwi.d.cts +23 -0
- package/dist/index.cjs +127 -14
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +1 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.js +27 -6
- package/dist/index.js.map +1 -1
- package/dist/management.cjs +352 -19
- package/dist/management.cjs.map +1 -1
- package/dist/management.d.cts +994 -42
- package/dist/management.d.ts +994 -42
- package/dist/management.js +352 -19
- package/dist/management.js.map +1 -1
- package/dist/nextjs.d.cts +1 -1
- package/dist/nextjs.d.ts +1 -1
- package/dist/nextjs.js +2 -1
- package/dist/nextjs.js.map +1 -1
- package/dist/server.cjs +103 -9
- package/dist/server.cjs.map +1 -1
- package/dist/server.d.cts +3 -105
- package/dist/server.d.ts +3 -105
- package/dist/server.js +1 -0
- package/package.json +16 -3
- package/dist/chunk-YGLMLIKL.js.map +0 -1
package/CHANGELOG.md
ADDED
|
@@ -0,0 +1,213 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
All notable changes to `@cboxdk/id-js` are recorded here. Earlier releases are described
|
|
4
|
+
in their [GitHub releases](https://github.com/cboxdk/id-js/releases).
|
|
5
|
+
|
|
6
|
+
## [Unreleased]
|
|
7
|
+
|
|
8
|
+
## [0.21.0] - 2026-11-08
|
|
9
|
+
|
|
10
|
+
### Added
|
|
11
|
+
|
|
12
|
+
- `@cboxdk/id-js/agent`: OpenID CIBA (poll mode) and the RFC 8628 device grant for agents and
|
|
13
|
+
CLIs, so they no longer need their own polling loop. `startBackchannel` / `pollBackchannel` /
|
|
14
|
+
`waitForBackchannelToken`, `startDeviceAuthorization` / `pollDeviceAuthorization` /
|
|
15
|
+
`waitForDeviceToken` and `refreshAgentTokens`. The wait helpers use the server's `interval`,
|
|
16
|
+
add 5 s on `slow_down` (and on 429, waiting at least `Retry-After`), keep polling on
|
|
17
|
+
`authorization_pending`, stop at `expires_in`, and take an `AbortSignal` and an injectable
|
|
18
|
+
`sleep`. `resource` (RFC 8707) is re-sent on every poll. No `user_code` is ever sent.
|
|
19
|
+
- `registerAgentClient()`: RFC 7591 dynamic registration with `private_key_jwt` (an ES256 or
|
|
20
|
+
RS256 key from `generateClientKeyPair()`, sent inline as `jwks`) or `none`.
|
|
21
|
+
`createClientAssertion()` signs the RFC 7523 assertion (`aud` = token endpoint, single-use
|
|
22
|
+
`jti`, at most 60 s). `startBackchannel` also accepts a keyless `none` client (sends
|
|
23
|
+
`client_id` only), which Cbox ID allows only where the resource permits it.
|
|
24
|
+
- `discoverAuthorizationServer()` reads `/.well-known/oauth-authorization-server` and checks
|
|
25
|
+
the issuer.
|
|
26
|
+
- `createBindingCode()`: a short code from an alphabet without look-alike characters, for the
|
|
27
|
+
`binding_message` that Cbox ID requires from self-registered clients.
|
|
28
|
+
- Typed errors: `AccessDeniedError`, `ExpiredTokenError`, `InvalidGrantError`,
|
|
29
|
+
`InvalidTargetError`, `InvalidClientError`, `UnknownUserIdError`,
|
|
30
|
+
`InvalidBindingMessageError`, `SlowDownError` (with `retryAfter`), all subclasses of
|
|
31
|
+
`AgentGrantError` (an `AuthenticationError`), plus `GrantCancelledError`.
|
|
32
|
+
- Guide: `docs/ciba-and-device-grant.md`.
|
|
33
|
+
|
|
34
|
+
## [0.20.0] - 2026-11-07
|
|
35
|
+
|
|
36
|
+
### Upgrade
|
|
37
|
+
|
|
38
|
+
Workspace team.remove requires its body with roles_version. Team writes use roles arrays and current CAS versions. Re-read state on conflicts. Live permission checks bind subject, organization and app; access-token role projections alone do not authorize sensitive actions.
|
|
39
|
+
|
|
40
|
+
### Added
|
|
41
|
+
|
|
42
|
+
- `checkPermissions()` and `PermissionDecision` for current server authorization, bound to the exact subject, organization and app. Decisions are never cached; malformed, redirected, oversized or unavailable responses fail closed.
|
|
43
|
+
- Updated management clients for multiple app roles, independent role and environment-access versions, scoped invitations and nullable member email.
|
|
44
|
+
|
|
45
|
+
### Changed
|
|
46
|
+
|
|
47
|
+
- Manifest publication requires a complete acknowledgement for the submitted client, version and checksum, including valid publication counts. Publishing definitions never assigns access.
|
|
48
|
+
- Workspace member removal now requires `roles_version` and removes native ID app roles only. Role edits require `roles` and `roles_version`; environment access uses its separate version.
|
|
49
|
+
|
|
50
|
+
## [0.19.0] - 2026-10-10
|
|
51
|
+
|
|
52
|
+
Needs laravel-id 1.24 / the Cbox ID release with feature flags, fine-grained
|
|
53
|
+
authorization, Pipes and SMS as a second factor. Against an older instance the new claim
|
|
54
|
+
reads as absent and the new endpoints answer 404.
|
|
55
|
+
|
|
56
|
+
### Added
|
|
57
|
+
|
|
58
|
+
- Feature flags: `featureFlags(source)` and `hasFeature(source, key)` read the
|
|
59
|
+
`feature_flags` claim from a signed-in user or a verified claim set, and
|
|
60
|
+
`CboxUser.featureFlags` carries it (`null` when the scope was not requested, `[]` when
|
|
61
|
+
nothing is on). `FEATURE_FLAGS_SCOPE` is the scope to request.
|
|
62
|
+
- Management API regenerated from the current specs: `env.featureFlags.*` (including
|
|
63
|
+
`evaluate({ user_id, organization_id })`), `env.fga.*` (check, `checkBatch`, tuples
|
|
64
|
+
write/delete/list, resources and subjects lists, schema get/update/validate, with
|
|
65
|
+
`consistency_token` on every read), `env.pipes.*` (pipe setup, grants, connections),
|
|
66
|
+
`env.radar.*`, `env.signin.sms.*`, the environment sign-in methods (`env.signin.social.*`
|
|
67
|
+
update/enable/disable/inherit/offered, `environment_wide` / `organization_id` on social
|
|
68
|
+
set, the auth policy's method fields), `env.branding.appearance.set()` taking the logo and
|
|
69
|
+
favicon as base64 data URIs, `env.users.mfa.sms.remove()`, the HRIS directory
|
|
70
|
+
routes (`env.directories.*`), and on the account plane `me.mfa.sms.remove()` and
|
|
71
|
+
`me.pipes.disconnect()`. `fgaTuple()` writes a tuple in the notation the batch check takes.
|
|
72
|
+
- Pipes: `VaultClient.leasePipeToken(provider, { userId?, purpose })` leases a fresh token
|
|
73
|
+
for a person's connected account. Refusals are typed: `PipeNotConnectedError` and
|
|
74
|
+
`PipeReauthorizationRequiredError` carry `connectUrl` (and `connectUrlWith({ clientId,
|
|
75
|
+
returnTo })`), `PipeTemporarilyUnavailableError` carries `retryAfter`,
|
|
76
|
+
`PipeLeaseDeniedError` is the 403. `client.pipeConnectUrl(provider, returnTo)` and
|
|
77
|
+
`pipeConnectUrl()` build the hosted connect page.
|
|
78
|
+
- `CboxIdFrontend.config({ organization })`: the sign-in document for one organization (by
|
|
79
|
+
id or slug), whose `social` list is exactly what that organization's hosted page offers.
|
|
80
|
+
Each organization is cached on its own. `FrontendConfig.methods` says whether passkeys and
|
|
81
|
+
magic links are switched on.
|
|
82
|
+
- Embedded sign-in: `mfa_required` lists the `factors` the person can answer with,
|
|
83
|
+
`CboxIdFrontend.sendSmsCode(mfaToken)` texts the code, and `submitSecondFactor()` accepts
|
|
84
|
+
`'sms'`.
|
|
85
|
+
|
|
86
|
+
### Changed
|
|
87
|
+
|
|
88
|
+
- The generator reads an action's own `202 Accepted` body (documented as `oneOf` it and the
|
|
89
|
+
approval body), so `env.directories.sync()` now returns the directory.
|
|
90
|
+
|
|
91
|
+
## [0.18.0] - 2026-10-08
|
|
92
|
+
|
|
93
|
+
### Added
|
|
94
|
+
|
|
95
|
+
- `verifyStandardWebhook()`: verifies deliveries from an endpoint on the `standard_webhooks`
|
|
96
|
+
signature scheme (`webhook-id` / `webhook-timestamp` / `webhook-signature`, any valid `v1`
|
|
97
|
+
signature, 5-minute window). Takes a `whsec_…` secret or an endpoint's 64-hex Cbox secret.
|
|
98
|
+
Tested against the Standard Webhooks specification's vector.
|
|
99
|
+
|
|
100
|
+
- `@cboxdk/id-js/management`: typed clients for Cbox ID's management planes, generated from
|
|
101
|
+
the OpenAPI documents the server publishes. `EnvironmentClient` (an environment's own host,
|
|
102
|
+
`cbid_env_…` key or delegated token), `WorkspaceClient` (`cbid_ws_…` key), `PlatformClient`
|
|
103
|
+
(operator token) and `AccountClient` (a person's own token). Methods are named after the
|
|
104
|
+
server's actions (`env.apps.secrets.rotate(id, body)`, `workspace.environments.create(body)`),
|
|
105
|
+
with typed bodies, queries and responses.
|
|
106
|
+
- Every write sends an `Idempotency-Key` (a fresh UUID unless you pass one) and is retried
|
|
107
|
+
with the same key on network failures, `5xx`, `429` and `409 idempotency_in_progress`,
|
|
108
|
+
respecting `Retry-After`. `replayed` reports `Idempotent-Replayed`.
|
|
109
|
+
- Approvals: a `202 approval_required` calls `onApprovalRequired` (show the binding code),
|
|
110
|
+
polls the approval and repeats the request with `Cbox-Approval` and the same key.
|
|
111
|
+
`ApprovalDeniedError` and `ApprovalExpiredError` when it is not approved;
|
|
112
|
+
`{ approval: 'return' }` hands back the pending approval with a `resume()`.
|
|
113
|
+
- `CboxIdApiError` (`status`, `error`, `message`, `errors`, `requestId` from the envelope's
|
|
114
|
+
`request_id` or `X-Request-Id`, `retryAfter`) and `ManagementNetworkError` (with the
|
|
115
|
+
`idempotencyKey` to repeat safely).
|
|
116
|
+
- `environment` on `EnvironmentClient`: with a person's root access token and the platform
|
|
117
|
+
root as `baseUrl`, it sends `Cbox-Environment` so one token can drive any environment of
|
|
118
|
+
the workspace.
|
|
119
|
+
- Audit Logs helpers: `AuditLogger` (buffers events and sends batches of up to 100, each
|
|
120
|
+
with its own Idempotency-Key, on size, interval and `flush()`), `exportAuditLogs()`
|
|
121
|
+
(creates an export and polls it until ready), and `verifyAuditChain()` /
|
|
122
|
+
`verifyAuditLogChain()` with `canonicalJson()` and `auditEventHash()`, which recompute an
|
|
123
|
+
organization's hash chain exactly as the server does.
|
|
124
|
+
- `…All` async iterators on every paged list (cursor and page-number paging).
|
|
125
|
+
- DPoP-bound access tokens: `createDPoPSigner()` and `generateDPoPKeyPair()` (ES256 on
|
|
126
|
+
WebCrypto, with `DPoP-Nonce` challenge handling).
|
|
127
|
+
- Operation tables (`environmentOperations`, …) with each action's method, path, scope, danger
|
|
128
|
+
(from the spec's `x-scope` / `x-danger`) and whether it can be held for approval.
|
|
129
|
+
- `npm run generate` regenerates the clients from the vendored specs in `openapi/`, and
|
|
130
|
+
`--fetch <plane>=<host>` refreshes a spec from a running server first. The test suite fails
|
|
131
|
+
when the two disagree.
|
|
132
|
+
|
|
133
|
+
## [0.17.0] - 2026-09-24
|
|
134
|
+
|
|
135
|
+
Organization selection and support sessions. Needs a Cbox ID instance that understands the
|
|
136
|
+
`organization` / `organization_hint` authorize parameters and emits `org_role` and `act`
|
|
137
|
+
(laravel-id 1.19). Against an older instance the new fields stay empty, and a switch fails
|
|
138
|
+
at the callback instead of silently landing in the old organization (see below).
|
|
139
|
+
|
|
140
|
+
### Added
|
|
141
|
+
|
|
142
|
+
- `createAuthorizationRequest()` accepts `organization` (bind the sign-in to one
|
|
143
|
+
organization), `organizationHint` (preselect it in the hosted picker), and the prompts
|
|
144
|
+
`select_organization` and `create_organization`.
|
|
145
|
+
- `client.switchOrganization(id)` and, on the Next.js adapter,
|
|
146
|
+
`cboxId.switchOrganization(id)`: a new authorization bound to another organization.
|
|
147
|
+
- The organization a sign-in was bound to is echoed on the `AuthorizationRequest` and
|
|
148
|
+
verified at the callback (`stored.organization`): tokens for any other organization are
|
|
149
|
+
refused. The Next.js adapter carries it in a `cbox_id_organization` cookie, and clears
|
|
150
|
+
that cookie on a plain sign-in so an abandoned switch cannot leak its binding into it.
|
|
151
|
+
- `CboxUser` gains typed `organization` (`{ id, name, role }` from `org`, `org_name`,
|
|
152
|
+
`org_role`), `roles`, `permissions` and `actor` (the RFC 8693 `act` claim).
|
|
153
|
+
- Claim helpers that work on a `CboxUser` or on a claim set you verified yourself:
|
|
154
|
+
`organization()`, `actor()`, `isSupportSession()`, `roles()`, `permissions()`,
|
|
155
|
+
`hasRole()`, `hasPermission()`.
|
|
156
|
+
- `client.apiKeysUrl({ clientId?, returnTo?, organization? })` (and `cboxId.apiKeysUrl()`
|
|
157
|
+
on the Next.js adapter): the hosted page where a person creates and revokes API keys for
|
|
158
|
+
your API, `/account/api-keys`, preselected to this app.
|
|
159
|
+
- `ApiKeyVerifier` in a new server-only entry, `@cboxdk/id-js/server`, and
|
|
160
|
+
`cboxId.verifyApiKey(key)` on the Next.js adapter: verifies a customer API key with
|
|
161
|
+
`POST /oauth/api-keys/verify` (HTTP Basic client auth) and returns the typed answer
|
|
162
|
+
`{ active, key_id, sub, org, org_role, permissions, client_id, expires_at }`. It refuses
|
|
163
|
+
an answer for any other `client_id`, treats a key past `expires_at` as inactive, refuses
|
|
164
|
+
to run in a browser, and has an optional cache of active answers (`cacheTtlMs`, at most
|
|
165
|
+
60 s, never past the key's expiry). Not exported from the main entry.
|
|
166
|
+
- `CboxUser.sessionId` and `sessionId()`: the ID Token's `sid`, the sign-in session a
|
|
167
|
+
back-channel logout token names.
|
|
168
|
+
- Staff roles: `tenantAssignable: false` on a `RoleDefinition` publishes the role as
|
|
169
|
+
staff-only (`tenant_assignable: false`), which Cbox ID never offers or accepts on an
|
|
170
|
+
organization's own admin pages.
|
|
171
|
+
- Self-serve permissions: `tenantAssignable: true` on a `PermissionDefinition` publishes it
|
|
172
|
+
as one an organization's administrators may put in their own custom roles
|
|
173
|
+
(`tenant_assignable: true`). Permissions stay internal by default.
|
|
174
|
+
- Exported wire types `ManifestPermission` and `ManifestRole`.
|
|
175
|
+
- Exported types `AuthorizationPrompt`, `AuthorizationRequestOptions`,
|
|
176
|
+
`OrganizationRole`, `CboxActiveOrganization`, `CboxActor`, `ClaimSource`,
|
|
177
|
+
`CboxOrganization`, and `SignInOptions` from `@cboxdk/id-js/nextjs`.
|
|
178
|
+
|
|
179
|
+
### Fixed
|
|
180
|
+
|
|
181
|
+
- `CboxIdConfig.accountPath` was documented as defaulting to `/settings`, which on Cbox ID
|
|
182
|
+
is the organization's settings page for its administrators. `profileUrl()` has actually
|
|
183
|
+
defaulted to the person's own account area, `/account`, since 0.8.0; the documentation
|
|
184
|
+
now says so. If you set `accountPath: '/settings'` because of it, remove it: members who
|
|
185
|
+
are not organization admins are redirected away from that page and lose `return_to`.
|
|
186
|
+
|
|
187
|
+
### Changed
|
|
188
|
+
|
|
189
|
+
- An error returned to the callback (`?error=access_denied`) now sets
|
|
190
|
+
`AuthenticationError.error` and `.errorDescription`, as the back-channel errors already
|
|
191
|
+
did. A refused organization switch is `access_denied`, and an app answers it by switching
|
|
192
|
+
back, not by signing the person out — which it could not tell apart before.
|
|
193
|
+
- `prompt` is typed as `AuthorizationPrompt | AuthorizationPrompt[]` instead of `string`,
|
|
194
|
+
and `prompt: 'none'` combined with another value is refused (OIDC Core §3.1.2.1).
|
|
195
|
+
**Breaking for TypeScript callers that pass a `string` variable**; narrow it to
|
|
196
|
+
`AuthorizationPrompt`.
|
|
197
|
+
- `organization` together with `prompt: 'select_organization'` or `'create_organization'`,
|
|
198
|
+
or an empty `organization` / `organizationHint`, throws `ConfigurationError` before any
|
|
199
|
+
redirect.
|
|
200
|
+
- The manifest `version` now covers both `tenant_assignable` flags, byte-for-byte as the
|
|
201
|
+
PHP reference hashes them: present only in their non-default state, so a catalog that
|
|
202
|
+
never sets them keeps the version it had. The shared cross-SDK fixture gained the
|
|
203
|
+
`staff_role` and `self_serve_permission` cases.
|
|
204
|
+
- `AuthzManifest.permissions` / `.roles` are typed as the wire shapes (`ManifestPermission`,
|
|
205
|
+
`ManifestRole`, snake_case flags) rather than as the declaration types.
|
|
206
|
+
- `defineAuthz()` / `buildManifest()` now refuse a key that is not a lowercase
|
|
207
|
+
`feature:action` slug, and a `tenantAssignable` that is not a boolean, with a
|
|
208
|
+
`ConfigurationError` — both were refused by the server on push anyway.
|
|
209
|
+
- A role that lists the same permission twice is sent and hashed with it once, as the
|
|
210
|
+
server stores it; the repeat used to give a `version` no server computes.
|
|
211
|
+
- `CboxUser` has five new required fields. Code that builds a `CboxUser` by hand (test
|
|
212
|
+
fixtures) must add `organization: null, roles: [], permissions: [], actor: null,
|
|
213
|
+
sessionId: null`.
|
package/README.md
CHANGED
|
@@ -189,12 +189,14 @@ access token's payload on a resource server:
|
|
|
189
189
|
```ts
|
|
190
190
|
import { organization, hasPermission, hasRole, isSupportSession } from '@cboxdk/id-js';
|
|
191
191
|
|
|
192
|
-
|
|
192
|
+
const showCreateHint = hasPermission(payload, 'invoices:create');
|
|
193
193
|
if (organization(user)?.role === 'owner') showBilling();
|
|
194
194
|
```
|
|
195
195
|
|
|
196
196
|
Matching is exact — `invoices:*` does not grant `invoices:delete`. An `org_role` this SDK
|
|
197
197
|
version does not recognise reads as `null`, never as a tier it would have to guess.
|
|
198
|
+
These are token snapshots for presentation. Protected operations require the fresh
|
|
199
|
+
`checkPermissions` decision described below; hiding a control is not authorization.
|
|
198
200
|
|
|
199
201
|
### Feature flags
|
|
200
202
|
|
|
@@ -274,6 +276,33 @@ want the person re-approving every hour.
|
|
|
274
276
|
See [Sign in from a CLI](https://github.com/cboxdk/cbox-id/blob/main/docs/getting-started/sign-in-from-a-cli.md)
|
|
275
277
|
for the protocol itself and where to store the tokens.
|
|
276
278
|
|
|
279
|
+
### Agents and self-registering CLIs (CIBA and device grant)
|
|
280
|
+
|
|
281
|
+
`@cboxdk/id-js/agent` is for a CLI or an agent that registers itself (RFC 7591) and gets a
|
|
282
|
+
token for a person without a redirect: OpenID CIBA, where the person taps Approve in Cbox ID,
|
|
283
|
+
or the device grant. It generates a `private_key_jwt` key with WebCrypto, signs the client
|
|
284
|
+
assertions, and polls following the server's rules (`interval`, `slow_down`, 429
|
|
285
|
+
`Retry-After`, expiry, Ctrl-C). Refusals are typed errors.
|
|
286
|
+
|
|
287
|
+
```ts
|
|
288
|
+
import { startBackchannel, waitForBackchannelToken, createBindingCode } from '@cboxdk/id-js/agent';
|
|
289
|
+
|
|
290
|
+
const code = createBindingCode(); // e.g. "K7QM", shown beside Approve
|
|
291
|
+
const authorization = await startBackchannel({
|
|
292
|
+
issuer, client, loginHint: 'ada@acme.com', scope: 'openid mcp:read',
|
|
293
|
+
bindingMessage: `Brain CLI: ${code}`, resource: 'https://app.cboxbrain.com/mcp',
|
|
294
|
+
});
|
|
295
|
+
console.log(`Approve in Cbox ID. Check that it shows ${code}.`);
|
|
296
|
+
const tokens = await waitForBackchannelToken({ issuer, client, authorization });
|
|
297
|
+
```
|
|
298
|
+
|
|
299
|
+
Self-registered clients must send `resource` and `binding_message`. Register with
|
|
300
|
+
`private_key_jwt` for CIBA: a keyless (`none`) client can use CIBA only where the resource
|
|
301
|
+
allows it, and is otherwise refused with `invalid_target`.
|
|
302
|
+
|
|
303
|
+
See [docs/ciba-and-device-grant.md](docs/ciba-and-device-grant.md) for when to use each flow,
|
|
304
|
+
a complete Node CLI and the error table.
|
|
305
|
+
|
|
277
306
|
## In the browser (publishable keys)
|
|
278
307
|
|
|
279
308
|
Everything above needs a server: it holds your client secret. A **publishable key** is the
|
|
@@ -619,8 +648,27 @@ the hosted connect page, preselected to your app; they come back with
|
|
|
619
648
|
|
|
620
649
|
Declare your app's authorization **roles** and **permissions** in code, then push them
|
|
621
650
|
to Cbox ID on deploy. Your app owns what a role *means*; Cbox ID owns identity and who
|
|
622
|
-
*holds* each role
|
|
623
|
-
|
|
651
|
+
*holds* each role. Publication requires the client's `apps.manifest` scope and a
|
|
652
|
+
server acknowledgement matching the client, version and full catalog checksum.
|
|
653
|
+
It does not assign roles. Expansions of existing roles await explicit activation.
|
|
654
|
+
|
|
655
|
+
Token role and permission claims are snapshots for presentation. Authorize protected
|
|
656
|
+
server requests and queued work using a fresh decision, then enforce your own row
|
|
657
|
+
ownership/organization rules. Shared organization Admin is not app Admin.
|
|
658
|
+
|
|
659
|
+
```ts
|
|
660
|
+
import { checkPermissions } from '@cboxdk/id-js/server';
|
|
661
|
+
|
|
662
|
+
const decision = await checkPermissions(
|
|
663
|
+
{ issuer, clientId }, accessToken, authenticatedSubject, selectedOrganization,
|
|
664
|
+
['invoices:create'],
|
|
665
|
+
);
|
|
666
|
+
if (!decision.allowed()) throw new Error('Forbidden');
|
|
667
|
+
```
|
|
668
|
+
|
|
669
|
+
Derive the subject from verified authentication and authorize the selected organization;
|
|
670
|
+
do not accept either as an unchecked form value. The check has no positive cache,
|
|
671
|
+
refuses redirects and rejects mismatched, incomplete or unavailable decisions.
|
|
624
672
|
|
|
625
673
|
```ts
|
|
626
674
|
import { defineAuthz, publishManifest } from '@cboxdk/id-js';
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
# id-js 0.20.0
|
|
2
|
+
|
|
3
|
+
Status: prepared local candidate. No public tag, registry publication or deployment has occurred.
|
|
4
|
+
|
|
5
|
+
Add request-bound live permission decisions and catalog checksums; regenerate app catalog, role-definition activation, invitations and native management APIs.
|
|
6
|
+
|
|
7
|
+
## Upgrade requirements
|
|
8
|
+
|
|
9
|
+
Workspace team.remove requires its body with roles_version. Team writes use roles arrays and current CAS versions. Re-read state on conflicts. Live permission checks bind subject, organization and app; access-token role projections alone do not authorize sensitive actions.
|
|
10
|
+
|
|
11
|
+
Dependency installation against public registries remains contingent on the approved release cascade. Local artifact checks prove the enclosed contents only; they do not claim public indexing.
|