@janssenproject/cedarling_wasm 0.0.467-nodejs → 0.0.468

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -1,87 +1,490 @@
1
- # Cedarling WASM
1
+ # Getting Started with Cedarling in a JavaScript App
2
2
 
3
- This module builds Cedarling's Rust implementation for WebAssembly. This guide
4
- covers building and testing the generated binding and running its local browser
5
- examples; JavaScript package consumers should use the npm package guide below.
3
+ The `@janssenproject/cedarling_wasm` package brings
4
+ [Cedarling](https://docs.jans.io/stable/cedarling/) authorization to JavaScript and
5
+ TypeScript applications. Cedarling evaluates Cedar policies within your
6
+ application's process, whether it runs in a browser, on a server, or at the edge.
7
+ It determines whether a principal or token set may perform an action on a resource.
6
8
 
7
- ## Choose the right guide
9
+ Use Cedarling to apply consistent access policies, inspect authorization decisions,
10
+ retain decision logs, and make application context available to policy evaluation.
8
11
 
9
- - For a JavaScript or TypeScript application, use the
10
- [npm package guide](./js/README.md).
11
- - For package generation, artifact qualification, and release maintenance, use
12
- the [maintainer guide](./js/docs/maintainer.md).
13
- - This guide covers direct development with the wasm-pack-generated binding.
12
+ ## Installation
14
13
 
15
- ## Building
14
+ ### Using the Package Manager
16
15
 
17
- For building we use [`wasm-pack`](https://developer.mozilla.org/en-US/docs/WebAssembly/Rust_to_Wasm) for install you can use command `cargo install wasm-pack`
16
+ ```sh
17
+ npm install @janssenproject/cedarling_wasm
18
+ ```
19
+
20
+ Choose the package entry for your application. The package ships Cedarling's
21
+ WebAssembly (`.wasm`) binary; the last column describes how that binary is loaded
22
+ and initialized. Your application's policy archive is configured separately.
23
+
24
+ | Environment | Package Entry | Packaged WASM Loading |
25
+ | -------------------------------------------- | --------------------------------------------------- | ----------------------------------- |
26
+ | Browser applications with supported bundlers | `@janssenproject/cedarling_wasm` | Automatic |
27
+ | Node.js 22, 24, or 26, ESM or CommonJS | `@janssenproject/cedarling_wasm` | Automatic |
28
+ | Cloudflare Workers and Vercel Edge | `@janssenproject/cedarling_wasm/edge` | Bundled as a precompiled module |
29
+ | Other ESM bundlers | `@janssenproject/cedarling_wasm/manual` and `/wasm` | Application-configured WASM loading |
30
+
31
+ Browser applications use an ESM-aware bundler. Follow
32
+ [Other Integration Paths](#other-integration-paths) for edge deployment and
33
+ application-controlled WASM loading.
34
+
35
+ ### Build from Source
36
+
37
+ For local generation, package build, and qualification instructions, see the
38
+ [maintainer guide](https://github.com/JanssenProject/jans/blob/main/jans-cedarling/bindings/cedarling_wasm/js/docs/maintainer.md).
39
+
40
+ ## Usage
18
41
 
19
- Build cedarling in release:
42
+ ### Initialization
20
43
 
21
- ```bash
22
- wasm-pack build --release --target web
44
+ Create a Cedarling instance with `init()`. It ensures the package's WASM binary is
45
+ loaded and initialized, then creates the instance using an object or `Map` of
46
+ canonical Cedarling bootstrap properties.
47
+
48
+ For browser or Node.js ESM applications:
49
+
50
+ ```ts
51
+ import { init } from "@janssenproject/cedarling_wasm";
52
+
53
+ const config = {
54
+ CEDARLING_APPLICATION_NAME: "task-api",
55
+ CEDARLING_LOG_TYPE: "memory",
56
+ CEDARLING_LOG_TTL: 120,
57
+ };
58
+ let cedarling;
59
+ try {
60
+ cedarling = await init({
61
+ ...config,
62
+ CEDARLING_POLICY_STORE_URI: "https://example.com/policy-store.cjar",
63
+ });
64
+ } catch (error) {
65
+ console.error("Cedarling initialization failed", error);
66
+ throw error;
67
+ }
23
68
  ```
24
69
 
25
- Build cedarling in dev mode
70
+ Replace the example URL with your application's policy archive. For Node.js
71
+ CommonJS, use the following import and run the initialization inside an async
72
+ function:
26
73
 
27
- ```bash
28
- wasm-pack build --target web --dev
74
+ ```js
75
+ const { init } = require("@janssenproject/cedarling_wasm");
29
76
  ```
30
77
 
31
- Result files will be in `pkg` folder.
78
+ The examples below reuse `cedarling`. Run each authorization walkthrough
79
+ separately, with a policy store that matches its entities and attributes.
80
+ Handle initialization failures in your application's startup error handler.
81
+ See the [bootstrap-property reference](https://docs.jans.io/stable/cedarling/reference/cedarling-properties/)
82
+ for configuration values, defaults, and token-validation settings.
83
+
84
+ ### Policy Store Sources
32
85
 
33
- ## Testing
86
+ A Cedar archive (`.cjar`) packages the schema, policies, and trusted-issuer
87
+ configuration. Prepare policies with the
88
+ [Agama Lab Policy Designer](https://cloud.gluu.org/agama-lab/dashboard/policy-designer)
89
+ and follow the [Cedar Archive format](https://docs.jans.io/nightly/cedarling/reference/cedarling-policy-store/#cedar-archive-cjar-format)
90
+ for packaging.
34
91
 
35
- For WASM testing we use `wasm-pack` and it allows to make test in `node`, `chrome`, `firefox`, `safari`. You just need specify appropriate flag.
92
+ #### Load a Cedar Archive from a URL
36
93
 
37
- Example for firefox.
94
+ Set `CEDARLING_POLICY_STORE_URI` as shown in [Initialization](#initialization).
95
+ Cedarling downloads the archive while creating the instance. Use an absolute
96
+ HTTP(S) URL. For browser downloads, use the application's origin or configure the
97
+ archive server's CORS headers to allow the application origin.
38
98
 
39
- ```bash
40
- wasm-pack test --firefox
99
+ #### Load a Cedar Archive from Bytes
100
+
101
+ Use `initFromArchiveBytes()` instead of `init()` when your application controls
102
+ the download. This browser example reuses `config` from Initialization and
103
+ fetches an archive through a same-origin application endpoint:
104
+
105
+ ```ts
106
+ import { initFromArchiveBytes } from "@janssenproject/cedarling_wasm";
107
+
108
+ let policyArchiveBytes;
109
+ let cedarling;
110
+ try {
111
+ const response = await fetch("/api/policy-store");
112
+ if (!response.ok) throw new Error("Policy-store download failed");
113
+ policyArchiveBytes = new Uint8Array(await response.arrayBuffer());
114
+ cedarling = await initFromArchiveBytes(config, policyArchiveBytes);
115
+ } catch (error) {
116
+ console.error("Policy-store download or initialization failed", error);
117
+ throw error;
118
+ }
41
119
  ```
42
120
 
43
- ## Run browser example
121
+ The archive bytes supply the policy store; `config` supplies the other bootstrap
122
+ properties. The package still loads and initializes its own WASM binary. In
123
+ Node.js, use an absolute download URL. Keep upstream policy-store credentials on
124
+ a trusted server; browser configuration is visible to its users.
44
125
 
45
- To run example using `index.html` you need execute following steps:
126
+ ### Authorization
46
127
 
47
- 1. Build wasm cedarling.
48
- 2. Run webserver using `python3 -m http.server` or any other.
49
- 3. Visit example app [localhost](http://localhost:8000/), on this app you will get log in browser console.
50
- - Also you can try use cedarling with web app using [cedarling_app](http://localhost:8000/cedarling_app.html), using custom bootstrap properties and request.
128
+ Choose token-based authorization when identity comes from JWTs, or unsigned
129
+ authorization when the application supplies a trusted principal. Both methods
130
+ accept a JSON-string request and return a promise that resolves to an authorization
131
+ result containing `decision` and `request_id`.
51
132
 
52
- ## WASM Usage
133
+ #### Token-Based Authorization (Multi-Issuer)
53
134
 
54
- After building WASM bindings in folder `pkg` you can find where you can find `cedarling_wasm.js` and `cedarling_wasm.d.ts` where is defined interface for application.
135
+ Use `authorizeMultiIssuer()` to evaluate tokens from one or more issuers. Your
136
+ policy store must define the token mappings, trusted issuers, resource schema,
137
+ action, and context used below. Configure token validation for those issuers;
138
+ the initialization example retains Cedarling's validation defaults.
55
139
 
56
- In `index.html` described simple usage of `cedarling wasm` API:
140
+ 1. Prepare the tokens.
57
141
 
58
- ```js
59
- import { BOOTSTRAP_CONFIG, REQUEST_UNSIGNED } from "/example_data.js"; // Import js objects: bootstrap config and request
60
- import initWasm, { init } from "/pkg/cedarling_wasm.js";
142
+ Obtain `acmeAccessToken` and `dolphinAccessToken` from your application's
143
+ authentication flows. Each `mapping` must match its policy-store token
144
+ metadata; each `payload` is the actual JWT string.
145
+
146
+ ```ts
147
+ const tokens = [
148
+ { mapping: "Acme::Access_Token", payload: acmeAccessToken },
149
+ { mapping: "Dolphin::Access_Token", payload: dolphinAccessToken },
150
+ ];
151
+ ```
152
+
153
+ 2. Define the resource.
154
+
155
+ This example targets a document. Its type and attributes must match your schema.
156
+
157
+ ```ts
158
+ const resource = {
159
+ cedar_entity_mapping: { entity_type: "Task::Document", id: "document-1" },
160
+ owner: "alice",
161
+ };
162
+ ```
163
+
164
+ 3. Define the action.
165
+
166
+ ```ts
167
+ const action = 'Task::Action::"Read"';
168
+ ```
169
+
170
+ 4. Define the context.
171
+
172
+ Supply request-specific data required by your policies and schema.
173
+
174
+ ```ts
175
+ const context = { tenant: "example" };
176
+ ```
177
+
178
+ 5. Build the request.
179
+
180
+ ```ts
181
+ const request = { tokens, action, resource, context };
182
+ ```
183
+
184
+ 6. Perform authorization and handle the decision.
185
+
186
+ ```ts
187
+ try {
188
+ const result = await cedarling.authorizeMultiIssuer(JSON.stringify(request));
189
+ console.log(result.decision ? "Allowed" : "Denied", result.request_id);
190
+ } catch (error) {
191
+ console.error("Authorization failed", error);
192
+ }
193
+ ```
194
+
195
+ #### Unsigned Authorization
196
+
197
+ Use `authorizeUnsigned()` when your application supplies the principal and its
198
+ attributes. Obtain those values from trusted application state. The policy store
199
+ for this example must define `Task::User` with a `role`, `Task::Document` with an
200
+ `owner`, and the `Read` action with the `tenant` context field.
201
+
202
+ 1. Prepare the principal.
203
+
204
+ ```ts
205
+ const principal = {
206
+ cedar_entity_mapping: { entity_type: "Task::User", id: "alice" },
207
+ role: "member",
208
+ };
209
+ ```
210
+
211
+ 2. Define the resource.
212
+
213
+ ```ts
214
+ const resource = {
215
+ cedar_entity_mapping: { entity_type: "Task::Document", id: "document-1" },
216
+ owner: "alice",
217
+ };
218
+ ```
219
+
220
+ 3. Define the action.
221
+
222
+ ```ts
223
+ const action = 'Task::Action::"Read"';
224
+ ```
225
+
226
+ 4. Define the context.
227
+
228
+ ```ts
229
+ const context = { tenant: "example" };
230
+ ```
231
+
232
+ 5. Build the request.
233
+
234
+ ```ts
235
+ const request = { principal, action, resource, context };
236
+ ```
237
+
238
+ 6. Perform authorization and handle the decision.
239
+
240
+ ```ts
241
+ try {
242
+ const result = await cedarling.authorizeUnsigned(JSON.stringify(request));
243
+ console.log(result.decision ? "Allowed" : "Denied", result.request_id);
244
+ } catch (error) {
245
+ console.error("Authorization failed", error);
246
+ }
247
+ ```
248
+
249
+ For both methods, `decision: false` is a valid denial. Malformed requests reject
250
+ the call. Multi-issuer authorization can continue with tokens that pass validation,
251
+ so policies must require the tokens needed for access. Perform the protected
252
+ operation only after receiving `decision: true`; enforce server-side access at the
253
+ server boundary.
254
+
255
+ #### Batch Authorization
256
+
257
+ Evaluate several resources with one principal or token set. Each item contains
258
+ an action, resource, and optional context. Reuse the values from the relevant
259
+ walkthrough:
260
+
261
+ ```ts
262
+ const items = [
263
+ { action, resource, context },
264
+ {
265
+ action,
266
+ resource: {
267
+ ...resource,
268
+ cedar_entity_mapping: { entity_type: "Task::Document", id: "document-2" },
269
+ },
270
+ context,
271
+ },
272
+ ];
273
+ ```
274
+
275
+ For the unsigned walkthrough:
276
+
277
+ ```ts
278
+ let batch;
279
+ try {
280
+ batch = await cedarling.authorizeUnsignedBatch(
281
+ JSON.stringify({ principal, items }),
282
+ );
283
+ } catch (error) {
284
+ console.error("Batch authorization failed", error);
285
+ throw error;
286
+ }
287
+ ```
288
+
289
+ For the token-based walkthrough, use this call instead:
290
+
291
+ ```ts
292
+ let batch;
293
+ try {
294
+ batch = await cedarling.authorizeMultiIssuerBatch(
295
+ JSON.stringify({ tokens, items }),
296
+ );
297
+ } catch (error) {
298
+ console.error("Batch authorization failed", error);
299
+ throw error;
300
+ }
301
+ ```
302
+
303
+ After a successful batch call, inspect each item in the same order as the
304
+ submitted `items`:
305
+
306
+ ```ts
307
+ for (const item of batch.results) {
308
+ if (item.is_ok) {
309
+ console.log(item.unwrap().decision ? "Allowed" : "Denied");
310
+ } else {
311
+ console.error(item.error?.category, item.error?.message);
312
+ }
313
+ }
314
+ ```
315
+
316
+ A valid denial has `is_ok === true` and a false decision. A per-item build error
317
+ has `is_ok === false`. The returned `batch_id` correlates the batch's decision logs.
318
+
319
+ ### Logging
320
+
321
+ The initialization example enables memory logging and retains entries for up to 120
322
+ seconds. Inside either authorization walkthrough's `try` block, use the returned
323
+ request ID to inspect its logs:
324
+
325
+ ```ts
326
+ const logs = cedarling.getLogsByRequestId(result.request_id);
327
+ console.log(logs);
328
+ ```
329
+
330
+ Log records are plain JavaScript objects. To retrieve and clear all retained logs
331
+ when your application is ready to consume them:
332
+
333
+ ```ts
334
+ try {
335
+ const retainedLogs = cedarling.popLogs();
336
+ console.log(retainedLogs);
337
+ } catch (error) {
338
+ console.error("Log retrieval failed", error);
339
+ }
340
+ ```
341
+
342
+ ### Context Data
343
+
344
+ Store application-scoped data for policy evaluation, then retrieve or remove it:
345
+
346
+ ```ts
347
+ try {
348
+ cedarling.pushDataCtx("user:alice", { plan: "pro" }, 3600n);
349
+ const value = cedarling.getDataCtx("user:alice");
350
+ console.log(value);
351
+ cedarling.removeDataCtx("user:alice");
352
+ } catch (error) {
353
+ console.error("Context-data operation failed", error);
354
+ }
355
+ ```
356
+
357
+ The optional TTL is a `bigint` number of seconds; omitting it uses the configured
358
+ default. Retrieval returns `null` when a value is absent or expired.
359
+
360
+ ### Trusted Issuer Readiness
61
361
 
62
- async function main() {
63
- await initWasm(); // Initialize the WebAssembly module
362
+ Before token-based authorization, inspect which configured issuers loaded and
363
+ which failed:
64
364
 
65
- let instance = await init(BOOTSTRAP_CONFIG);
66
- // authorize calls take the request as a JSON string: it crosses the
67
- // JS/WASM boundary as one string copy parsed by serde_json
68
- let result = await instance.authorizeUnsigned(JSON.stringify(REQUEST_UNSIGNED));
69
- console.log("result:", result);
365
+ ```ts
366
+ console.log("Loaded issuers", cedarling.loadedTrustedIssuerIds());
367
+ console.log("Failed issuers", cedarling.failedTrustedIssuerIds());
368
+ ```
369
+
370
+ To check one issuer, pass its configured identifier to
371
+ `cedarling.isTrustedIssuerLoadedByName(issuerId)`.
372
+
373
+ ### Policy Annotations
374
+
375
+ Annotations attach metadata such as descriptions to policies using
376
+ `@key("value")`. They describe policies independently of their authorization rules.
377
+ For example, a policy in your archive can include:
378
+
379
+ ```cedar
380
+ @description("Allows Alice to read document-1")
381
+ permit (
382
+ principal == Task::User::"alice",
383
+ action == Task::Action::"Read",
384
+ resource == Task::Document::"document-1"
385
+ );
386
+ ```
387
+
388
+ Inside the unsigned walkthrough's `try` block, retrieve descriptions for the
389
+ determining policy IDs returned in the result:
390
+
391
+ ```ts
392
+ const descriptions = cedarling.annotationValues(
393
+ result.response.diagnostics.reason,
394
+ "description",
395
+ );
396
+ console.log(descriptions);
397
+ ```
398
+
399
+ See the [Cedar annotation reference](https://docs.cedarpolicy.com/policies/syntax-policy.html#annotations)
400
+ for annotation syntax and behavior.
401
+
402
+ ### Shutdown
403
+
404
+ When the application finishes using a Cedarling instance, shut it down:
405
+
406
+ ```ts
407
+ try {
408
+ await cedarling.shutDown();
409
+ } catch (error) {
410
+ console.error("Cedarling shutdown failed", error);
70
411
  }
71
- main().catch(console.error);
72
412
  ```
73
413
 
74
- When importing the generated glue directly from `pkg/`, call `initWasm()` before
75
- using the binding. The npm package's automatic entries handle this initialization.
414
+ ### Other Integration Paths
415
+
416
+ #### Edge Deployments
417
+
418
+ Use the ESM-only `./edge` entry in hosts whose deployment tool bundles the package's
419
+ WASM binary as a precompiled WebAssembly module. In Cloudflare Workers, initialize inside
420
+ the [request context](https://developers.cloudflare.com/workers/runtime-apis/request/#the-request-context)
421
+ so policy downloads can run:
422
+
423
+ ```ts
424
+ import { init } from "@janssenproject/cedarling_wasm/edge";
425
+
426
+ export default {
427
+ async fetch() {
428
+ let cedarling;
429
+ try {
430
+ cedarling = await init({
431
+ CEDARLING_APPLICATION_NAME: "edge-api",
432
+ CEDARLING_POLICY_STORE_URI: "https://example.com/policy-store.cjar",
433
+ });
434
+ return new Response("Cedarling initialized");
435
+ } catch (error) {
436
+ console.error("Cedarling initialization failed", error);
437
+ return new Response("Internal server error", { status: 500 });
438
+ } finally {
439
+ try {
440
+ await cedarling?.shutDown();
441
+ } catch (error) {
442
+ console.error("Cedarling shutdown failed", error);
443
+ }
444
+ }
445
+ },
446
+ };
447
+ ```
448
+
449
+ #### Manual Bundler Integration
450
+
451
+ For application-controlled WASM loading, configure your ESM bundler to emit the
452
+ package's `./wasm` export as a URL-addressable binary asset. Configure the server
453
+ to serve it with the `application/wasm` content type. The example below reuses
454
+ `config` and `policyArchiveBytes` from
455
+ [Load a Cedar Archive from Bytes](#load-a-cedar-archive-from-bytes), replacing
456
+ that section's initialization call:
457
+
458
+ ```ts
459
+ import initWasm, {
460
+ initFromArchiveBytes,
461
+ } from "@janssenproject/cedarling_wasm/manual";
462
+ import wasmUrl from "@janssenproject/cedarling_wasm/wasm";
463
+
464
+ let cedarling;
465
+ try {
466
+ await initWasm({ module_or_path: wasmUrl });
467
+ cedarling = await initFromArchiveBytes(config, policyArchiveBytes);
468
+ } catch (error) {
469
+ console.error("WASM loading or Cedarling initialization failed", error);
470
+ throw error;
471
+ }
472
+ ```
473
+
474
+ Configure the `.wasm` import to return an asset URL; the exact rule or plugin
475
+ depends on your bundler.
476
+
477
+ ## Upgrading Existing Applications
76
478
 
77
- ## API contract
479
+ Update calls such as `authorize_unsigned()` to `authorizeUnsigned()`,
480
+ `shut_down()` to `shutDown()`, and `json_string()` to `jsonString()`.
481
+ Bootstrap keys (`CEDARLING_*`), request JSON, result/data fields such as
482
+ `request_id`, and serialized JSON retain their names.
78
483
 
79
- `pkg/cedarling_wasm.d.ts` is the authoritative direct WebAssembly API after a
80
- successful build. Callable JavaScript APIs use camelCase, including
81
- `jsonString()`. Cedarling bootstrap properties, request JSON keys, and returned
82
- data fields retain their canonical names, including snake_case fields such as
83
- `request_id`.
484
+ ## See Also
84
485
 
85
- For portable npm consumption across browser, Node.js ESM, Node.js CommonJS,
86
- edge, and manual bundler paths, use `@janssenproject/cedarling_wasm` and its
87
- consumer guide instead of importing files under `pkg/`.
486
+ - [JavaScript tutorial](https://docs.jans.io/stable/cedarling/tutorials/javascript/)
487
+ - [Full API reference](https://docs.jans.io/stable/cedarling/tutorials/javascript/#defined-api)
488
+ - [Bootstrap-property reference](https://docs.jans.io/stable/cedarling/reference/cedarling-properties/)
489
+ - [Cedar Archive format](https://docs.jans.io/nightly/cedarling/reference/cedarling-policy-store/#cedar-archive-cjar-format)
490
+ - [Maintainer guide](https://github.com/JanssenProject/jans/blob/main/jans-cedarling/bindings/cedarling_wasm/js/docs/maintainer.md)