zuplo 6.72.2 → 6.72.7

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (61) hide show
  1. package/docs/analytics/access-and-entitlements.md +27 -34
  2. package/docs/analytics/overview.md +7 -6
  3. package/docs/analytics/reference/url-parameters.md +2 -10
  4. package/docs/analytics/shared-controls.md +3 -10
  5. package/docs/analytics/tabs/agents.md +3 -3
  6. package/docs/analytics/tabs/requests.md +2 -4
  7. package/docs/articles/accounts/audit-logs.mdx +4 -4
  8. package/docs/articles/audit-logging.mdx +65 -0
  9. package/docs/articles/audit-logs.mdx +222 -0
  10. package/docs/articles/connect-to-aws-alb-with-mtls.mdx +89 -13
  11. package/docs/articles/{custom-audit-log-policy.mdx → custom-audit-logs.mdx} +26 -22
  12. package/docs/articles/graphql-security.mdx +2 -1
  13. package/docs/articles/graphql.mdx +8 -0
  14. package/docs/articles/opentelemetry.mdx +7 -5
  15. package/docs/articles/securing-backend-mtls.mdx +92 -3
  16. package/docs/articles/troubleshooting-slow-responses.mdx +4 -3
  17. package/docs/articles/troubleshooting.md +3 -1
  18. package/docs/policies/_index.md +3 -0
  19. package/docs/policies/audit-log-inbound/doc.md +16 -11
  20. package/docs/policies/authzen-inbound/schema.json +1 -1
  21. package/docs/policies/axiomatics-authz-inbound/schema.json +1 -1
  22. package/docs/policies/clerk-jwt-auth-inbound/schema.json +3 -3
  23. package/docs/policies/mcp-auth0-oauth-inbound/schema.json +8 -5
  24. package/docs/policies/mcp-clerk-oauth-inbound/schema.json +78 -0
  25. package/docs/policies/mcp-cognito-oauth-inbound/schema.json +78 -0
  26. package/docs/policies/mcp-entra-oauth-inbound/schema.json +78 -0
  27. package/docs/policies/mcp-google-oauth-inbound/schema.json +78 -0
  28. package/docs/policies/mcp-keycloak-oauth-inbound/schema.json +78 -0
  29. package/docs/policies/mcp-logto-oauth-inbound/schema.json +78 -0
  30. package/docs/policies/mcp-oauth-inbound/schema.json +8 -5
  31. package/docs/policies/mcp-okta-oauth-inbound/schema.json +78 -0
  32. package/docs/policies/mcp-onelogin-oauth-inbound/schema.json +78 -0
  33. package/docs/policies/mcp-ping-oauth-inbound/schema.json +78 -0
  34. package/docs/policies/mcp-token-exchange-inbound/doc.md +72 -4
  35. package/docs/policies/mcp-token-exchange-inbound/intro.md +5 -4
  36. package/docs/policies/mcp-token-exchange-inbound/schema.json +277 -2
  37. package/docs/policies/mcp-workos-oauth-inbound/schema.json +78 -0
  38. package/docs/policies/mtls-auth-inbound/intro.md +52 -5
  39. package/docs/policies/okta-fga-authz-inbound/schema.json +1 -1
  40. package/docs/policies/open-id-jwt-auth-inbound/schema.json +3 -3
  41. package/docs/policies/openfga-authz-inbound/schema.json +1 -1
  42. package/docs/policies/propel-auth-jwt-inbound/schema.json +3 -3
  43. package/docs/policies/require-user-claims-inbound/doc.md +120 -0
  44. package/docs/policies/require-user-claims-inbound/intro.md +9 -0
  45. package/docs/policies/require-user-claims-inbound/schema.json +1323 -0
  46. package/docs/policies/semantic-cache-inbound/schema.json +1 -1
  47. package/docs/policies/upstream-aws-federated-auth-inbound/doc.md +78 -0
  48. package/docs/policies/upstream-aws-federated-auth-inbound/intro.md +20 -0
  49. package/docs/policies/upstream-aws-federated-auth-inbound/schema.json +98 -0
  50. package/docs/policies/upstream-aws-service-auth-inbound/doc.md +89 -0
  51. package/docs/policies/upstream-aws-service-auth-inbound/intro.md +19 -0
  52. package/docs/policies/upstream-aws-service-auth-inbound/schema.json +113 -0
  53. package/docs/policies/upstream-azure-ad-service-auth-inbound/schema.json +4 -4
  54. package/docs/policies/upstream-gcp-federated-auth-inbound/doc.md +2 -2
  55. package/docs/policies/upstream-gcp-federated-auth-inbound/schema.json +5 -5
  56. package/docs/policies/upstream-gcp-service-auth-inbound/doc.md +3 -3
  57. package/docs/policies/upstream-gcp-service-auth-inbound/schema.json +3 -3
  58. package/docs/policies/upstream-zuplo-jwt-auth-inbound/schema.json +19 -0
  59. package/docs/programmable-api/overview.mdx +0 -7
  60. package/package.json +4 -4
  61. package/docs/programmable-api/audit-log.mdx +0 -74
@@ -1,29 +1,22 @@
1
1
  ---
2
- title: Custom Audit Logging Policy
3
- sidebar_label: Audit Logging
2
+ title: Custom Audit Logs
3
+ sidebar_label: Custom Audit Logs
4
4
  ---
5
5
 
6
- This guide explains how to add custom audit logging beyond the scope of the
7
- `AuditLogsInboundPolicy`.
6
+ [Zuplo Audit Logs](./audit-logs.mdx) stores your audit trail in Zuplo and gives
7
+ you a portal viewer and query API out of the box. If your organization uses an
8
+ external audit logging service instead, you can send events to it directly from
9
+ the gateway with a [custom policy](../policies/custom-code-inbound.mdx) that
10
+ uses [runtime hooks](../programmable-api/runtime-extensions.mdx). This approach
11
+ works on any plan — it's just custom code — and gives you full control over
12
+ which events are recorded, the event format, and the destination.
8
13
 
9
- Audit logging is an important part of API security that plays a critical role in
10
- detecting and correcting issues such as unauthorized access or permission
11
- elevations within your system. Audit logging is also a requirement for many
12
- compliance certifications as well as part of the buying criteria for larger
13
- enterprises.
14
-
15
- Adding Audit Logging to your APIs that are secured with Zuplo is as easy as
16
- adding a custom policy. Typically you want to add audit logs to any API that
17
- modifies data, however depending on the API you may want it on read operations
18
- as well (for example retrieve a secret key, etc.)
19
-
20
- ## Example Policy: WorkOS Audit Logs
14
+ ## Example: WorkOS Audit Logs
21
15
 
22
16
  [WorkOS](https://workos.com/) provides various services that help enable
23
- enterprise features on your service such as SSO and Audit Logs. With Zuplo it's
24
- easy to create a [custom policy](../policies/custom-code-inbound.mdx) that uses
25
- [runtime hooks](../programmable-api/runtime-extensions.mdx) to log API calls
26
- using their API.
17
+ enterprise features on your service such as SSO and Audit Logs. The following
18
+ custom policy logs API calls to the WorkOS Audit Logs API after each response is
19
+ sent:
27
20
 
28
21
  ```ts
29
22
  import { ZuploContext, ZuploRequest, environment } from "@zuplo/runtime";
@@ -34,7 +27,7 @@ export async function auditLogPlugin(
34
27
  policyName: string,
35
28
  ) {
36
29
  // Clone the request so the body can be read in the hook
37
- // note: remove this is you don't need content from the body
30
+ // note: remove this if you don't need content from the body
38
31
  const cloned = request.clone();
39
32
  context.addResponseSendingFinalHook(async (response) => {
40
33
  const incomingBody = await cloned.json();
@@ -48,7 +41,7 @@ export async function auditLogPlugin(
48
41
  version: 1,
49
42
  actor: {
50
43
  type: "user",
51
- // Add the use the user sub for authenticated users
44
+ // Use the user sub for authenticated users
52
45
  id: request.user.sub,
53
46
  metadata: {
54
47
  role: "user",
@@ -93,3 +86,14 @@ export async function auditLogPlugin(
93
86
  return request;
94
87
  }
95
88
  ```
89
+
90
+ The same pattern works for any provider with an HTTP API — swap the event shape
91
+ and endpoint for your provider's, and store credentials in
92
+ [environment variables](./environment-variables.mdx).
93
+
94
+ ## Related resources
95
+
96
+ - [Audit logging overview](./audit-logging.mdx) — why audit logging matters and
97
+ how the options compare
98
+ - [Zuplo Audit Logs](./audit-logs.mdx) — the built-in feature with portal
99
+ viewing and a query API
@@ -180,7 +180,8 @@ outbound filter policy goes in the `outbound` array:
180
180
  ## Example repository
181
181
 
182
182
  For a complete, runnable setup, see the
183
- [GraphQL API with Zuplo example repository](https://github.com/zuplo/zuplo-graphql-example).
183
+ [GraphQL API with Zuplo example repository](https://github.com/zuplo-samples/graphql).
184
+ You can [deploy it to your own account in one click](./graphql.mdx).
184
185
 
185
186
  ## Next steps
186
187
 
@@ -12,6 +12,14 @@ Zuplo has rich support for GraphQL. Pass your requests through the gateway,
12
12
  attach policies, track operations with analytics, and publish documentation for
13
13
  your schema in the Dev Portal. This guide walks you through setting it up.
14
14
 
15
+ <ZupIt repoUrl="https://github.com/zuplo-samples/graphql">
16
+
17
+ Want to see it working first? This example proxies a public GraphQL API with
18
+ edge caching, query depth limiting, and analytics already wired up — deploy it
19
+ to your own Zuplo account in one click.
20
+
21
+ </ZupIt>
22
+
15
23
  :::tip{title="TL;DR"}
16
24
 
17
25
  - [ ] Proxy your GraphQL endpoint through a POST `/graphql` route with the URL
@@ -7,10 +7,9 @@ Zuplo ships with an OpenTelemetry plugin (`@zuplo/otel`) that instruments your
7
7
  API and exports traces and logs in OpenTelemetry format. The quickest way to use
8
8
  it is Zuplo's built-in tracing: add the plugin and your traces are stored by
9
9
  Zuplo and shown in the portal's **Observability** tab, with no collector to run
10
- or backend to host. You can also export to your own OpenTelemetry backend, or to
11
- both at once.
12
-
13
- <EnterpriseFeature name="OpenTelemetry" />
10
+ or backend to host. Built-in tracing is available on every plan. You can also
11
+ export to your own OpenTelemetry backend (an Enterprise feature), or to both at
12
+ once.
14
13
 
15
14
  ## Tracing
16
15
 
@@ -68,7 +67,8 @@ Deploy your project and open the **Observability** tab to see traces.
68
67
  Each trace is tagged with the account, project, deployment, and environment it
69
68
  ran in, plus the request ID (the `zp-rid` value) that also appears on your
70
69
  [logs](#logging), so you can move between a request's logs and its trace. How
71
- long traces are kept depends on your plan.
70
+ long traces are kept depends on your plan — see
71
+ [data retention](../analytics/access-and-entitlements.md#data-retention).
72
72
 
73
73
  :::note
74
74
 
@@ -81,6 +81,8 @@ still run.
81
81
 
82
82
  ### Export to Your Own Backend
83
83
 
84
+ <EnterpriseFeature name="Exporting to your own OpenTelemetry backend" />
85
+
84
86
  To send traces to an OpenTelemetry service such as
85
87
  [Honeycomb](https://honeycomb.io), [Middleware](https://middleware.io/),
86
88
  [Dynatrace](https://dynatrace.com), [Jaeger](https://www.jaegertracing.io/), or
@@ -30,11 +30,38 @@ gateways, and Zuplo can verify it's connecting to the correct backend service.
30
30
 
31
31
  Before you begin, you need:
32
32
 
33
- - A client certificate and private key generated from a Certificate Authority
34
- (CA) that your backend trusts
33
+ - A PEM-encoded client certificate and matching private key generated from a
34
+ Certificate Authority (CA) that your backend trusts
35
35
  - Your backend service configured to require and validate client certificates
36
36
  - The Zuplo CLI installed (see [CLI documentation](../cli/overview.mdx))
37
37
 
38
+ ## Client certificate requirements
39
+
40
+ The certificate uploaded to Zuplo is the client, or leaf, certificate that the
41
+ gateway presents to your backend. It should have the following properties:
42
+
43
+ - X.509 version 3
44
+ - `Basic Constraints: critical, CA:FALSE`
45
+ - `Key Usage: critical, Digital Signature`
46
+ - `Extended Key Usage: TLS Web Client Authentication` (`clientAuth`)
47
+ - An RSA key between 2048 and 8192 bits, or an ECDSA key using P-256, P-384, or
48
+ P-521
49
+ - A SHA-256 or stronger signature
50
+ - A subject that uniquely identifies the gateway credential
51
+ - A validity period appropriate for your certificate rotation policy
52
+
53
+ The issuing CA certificate must be X.509 version 3 with
54
+ `Basic Constraints: critical, CA:TRUE` and a key usage that includes
55
+ `Certificate Sign` and `CRL Sign`. Your backend's trust store must contain the
56
+ CA certificates needed to build a path from the client certificate to a trusted
57
+ root. When the trusted CA directly signs the client certificate, you do not need
58
+ a client certificate-chain bundle. If an intermediate CA signs it, follow your
59
+ backend's requirements for presenting and trusting the intermediate chain.
60
+
61
+ The private key must match the public key in the client certificate. Keep it
62
+ secret and limit access to it. The key must be unencrypted when uploaded to
63
+ Zuplo so the gateway can use it without a passphrase.
64
+
38
65
  ## 1/ Upload Your Certificate
39
66
 
40
67
  Use the Zuplo CLI to upload your client certificate and private key to your
@@ -229,10 +256,72 @@ For local development, consider:
229
256
 
230
257
  ### Certificate Validation Errors
231
258
 
232
- If your backend rejects the certificate, verify:
259
+ Inspect the certificate and confirm its subject, issuer, validity, and client
260
+ authentication purpose:
261
+
262
+ ```bash
263
+ openssl x509 \
264
+ -in client.crt \
265
+ -noout \
266
+ -subject \
267
+ -issuer \
268
+ -serial \
269
+ -dates \
270
+ -purpose
271
+ ```
272
+
273
+ `SSL client` should report `Yes`. To inspect all extensions, run
274
+ `openssl x509 -in client.crt -noout -text` and confirm the certificate reports
275
+ `CA:FALSE`, `Digital Signature`, and `TLS Web Client Authentication`.
276
+
277
+ Check that the certificate will remain valid for at least seven days:
278
+
279
+ ```bash
280
+ openssl x509 -in client.crt -noout -checkend 604800
281
+ ```
282
+
283
+ Validate the certificate path against the same CA bundle your backend trusts:
284
+
285
+ ```bash
286
+ openssl verify \
287
+ -verbose \
288
+ -purpose sslclient \
289
+ -x509_strict \
290
+ -show_chain \
291
+ -CAfile backend-client-ca-bundle.pem \
292
+ client.crt
293
+ ```
294
+
295
+ The expected result is `client.crt: OK`. Common errors include:
296
+
297
+ - `unable to get local issuer certificate`: The issuing CA or an intermediate CA
298
+ is missing from the backend's trust bundle.
299
+ - `unsupported certificate purpose`: The client certificate is missing the
300
+ `clientAuth` extended key usage.
301
+ - `certificate has expired`: The client certificate is outside its validity
302
+ period.
303
+ - `invalid CA certificate`: An issuing certificate is missing valid CA
304
+ extensions.
305
+ - `key usage does not include certificate signing`: An issuing CA does not have
306
+ the `keyCertSign` key usage.
307
+
308
+ Confirm that the certificate and private key contain the same public key:
309
+
310
+ ```bash
311
+ CERT_KEY_HASH=$(openssl x509 -in client.crt -noout -pubkey | openssl sha256)
312
+ PRIVATE_KEY_HASH=$(openssl pkey -in client.key -pubout | openssl sha256)
313
+
314
+ test "$CERT_KEY_HASH" = "$PRIVATE_KEY_HASH" &&
315
+ echo "Certificate and private key match" ||
316
+ echo "ERROR: Certificate and private key do not match"
317
+ ```
318
+
319
+ If your backend still rejects the certificate, verify:
233
320
 
234
321
  - The certificate is signed by a CA that your backend trusts
235
322
  - The certificate hasn't expired
323
+ - The certificate has the required key usage and extended key usage
324
+ - The certificate and private key match
236
325
  - The certificate name in your code matches the uploaded certificate name
237
326
 
238
327
  ### Connection Failures
@@ -240,9 +240,10 @@ For the most detailed view of where time is spent in your request pipeline,
240
240
  enable [OpenTelemetry tracing](./opentelemetry.mdx). The OpenTelemetry plugin
241
241
  automatically instruments your API and provides span-level timing for each stage
242
242
  of the request lifecycle — including inbound policies, the handler, outbound
243
- policies, and any subrequests made via `fetch` in custom code.
244
-
245
- <EnterpriseFeature name="OpenTelemetry" />
243
+ policies, and any subrequests made via `fetch` in custom code. Built-in tracing
244
+ is available on every plan; see
245
+ [data retention](../analytics/access-and-entitlements.md#data-retention) for how
246
+ much trace history you can query.
246
247
 
247
248
  With tracing enabled, you can see exactly how long each policy and handler takes
248
249
  to execute, making it straightforward to identify which component is adding
@@ -179,7 +179,9 @@ const response = await fetch("https://api.example.com/data", {
179
179
  The Zuplo Portal provides real-time log viewing for deployed environments. Open
180
180
  the **Observability** tab in your project — the **Logs** view opens by default —
181
181
  then use the **Environment** filter to select the deployed environment and see
182
- live request logs and any messages logged with `context.log`.
182
+ live request logs and any messages logged with `context.log`. How far back you
183
+ can search depends on your plan — see
184
+ [Access and entitlements](../analytics/access-and-entitlements.md#data-retention).
183
185
 
184
186
  ### Using context.log
185
187
 
@@ -91,6 +91,7 @@
91
91
  | request-size-limit-inbound | Request Size Limit | Enforces a maximum size in bytes of the incoming request. | api-gateway |
92
92
  | request-validation-inbound | Request Validation | Validates incoming requests against your OpenAPI specification. Checks query parameters, path parameters, headers, and request body to ensure they match the defined schema before processing. | api-gateway |
93
93
  | require-origin-inbound | Require Origin | Sets an allow-list for an origin header | api-gateway |
94
+ | require-user-claims-inbound | Require User Claims | Authorizes requests by validating claims on the authenticated user (`request.user`) against a configurable rule of `and`/`or` combinators and per-claim `eq`, `in`, and `startsWith` checks. Run it after any authentication policy that populates `request.user` — a JWT auth policy, API key auth, mTLS, and so on — to allow only specific callers (service accounts, OAuth clients, tenants, groups) without writing custom code. Every check fails closed: a missing or non-primitive claim never matches, comparisons are strict and type-sensitive, and requests without an authenticated user receive a 401 response. Denied requests receive a 403 response that does not echo claim values or expected values; the failing checks are written to the request log instead. Validation of the options runs lazily inside the policy constructor, which the runtime caches per policy name. Misconfigured options therefore fail on first use with a customer-facing `ConfigurationError` instead of failing at module load. | api-gateway |
94
95
  | secret-masking-outbound | Secret Masking | Masks common secrets like Zuplo API keys, GitHub tokens, or SSH private key in the response body. | api-gateway |
95
96
  | semantic-cache-inbound | Semantic Cache | Respond to matched incoming requests with semantically cached content The Semantic Cache Inbound policy caches responses based on semantic similarity of cache keys rather than exact matches. This allows for more flexible caching where similar requests can return cached responses even if the cache key is not exactly the same. The policy uses Large Language Model (LLM) embeddings to determine semantic similarity between cache keys based on a configurable similarity tolerance. Options: - semanticTolerance: The semantic similarity threshold for semantic cache matches (0-1, default: 0.2). Values closer to 0 require higher similarity. Can be overridden by custom functions. - expirationSecondsTtl: The timeout of the cache in seconds (default: 3600, 1 hour). Can be overridden by custom functions. - namespace: Optional namespace to isolate cache entries (default: "default"). Useful for multi-tenant scenarios or different cache contexts. - cacheBy: Determines how cache keys are generated: 'function' for custom logic or 'propertyPath' to extract from JSON body. | ai-gateway |
96
97
  | set-body-inbound | Set Body | Sets the body of the request in the inbound pipeline - make sure to convert a GET/HEAD request to another method when using this policy. | api-gateway |
@@ -103,6 +104,8 @@
103
104
  | traffic-splitting-inbound | Traffic Splitting | Splits traffic randomly across a set of weighted base paths. On each request one base path is selected (weighted by `weight`) and written to the request custom context at `customOutputProperty`. Reference it from a later URL Rewrite `rewritePattern` or URL Forward `baseUrl`, e.g. `${context.custom.trafficSplitting.basePath}`. | api-gateway |
104
105
  | transform-body-inbound | Transform Request Body | Transform the body of an incoming request. | api-gateway |
105
106
  | transform-body-outbound | Transform Response Body | Transform the body of an outgoing response. | api-gateway |
107
+ | upstream-aws-federated-auth-inbound | Upstream AWS Federated Auth | Resolves AWS credentials with STS AssumeRoleWithWebIdentity using Zuplo's ambient OIDC identity — no AWS keys are stored anywhere. The role's trust policy must trust the Zuplo OIDC identity provider. Resolved credentials are registered on the request context for the AWS Lambda handler and custom code to sign upstream requests with `AwsClient.fromContext`. This policy does not itself sign or forward the request. | api-gateway |
108
+ | upstream-aws-service-auth-inbound | Upstream AWS Service Auth | Resolves AWS credentials from static access keys (optionally exchanged for an IAM role's temporary credentials via STS AssumeRole) and registers them on the request context. The AWS Lambda handler and custom code read them with `AwsClient.fromContext` to sign upstream requests. This policy does not itself sign or forward the request. | api-gateway |
106
109
  | upstream-azure-ad-service-auth-inbound | Upstream Azure AD Service Auth | Uses Azure Active Directory to add an Authorization header to the request in order to authenticate requests using Azure identity. | api-gateway |
107
110
  | upstream-firebase-admin-auth-inbound | Upstream Firebase Admin Auth | Creates a Firebase Admin token and attaches it to the outgoing request. Useful when calling Firebase services as an administrator. | api-gateway |
108
111
  | upstream-firebase-user-auth-inbound | Upstream Firebase User Auth | Creates a Firebase custom user token and attaches it to the outgoing request. Useful when calling Firebase services as user. | api-gateway |
@@ -16,14 +16,14 @@ requests).
16
16
  ## Controlling What's Logged
17
17
 
18
18
  Audit events can contain personal or sensitive data. To keep audit logging
19
- compliant with your own data-handling and PII policies, use the `include`
20
- option to turn individual fields off. Everything is captured by default; set a
21
- flag to `false` to omit it:
19
+ compliant with your own data-handling and PII policies, use the `include` option
20
+ to turn individual fields off. Everything is captured by default; set a flag to
21
+ `false` to omit it:
22
22
 
23
23
  - `queryParams` — the request's query-string parameters (in the logged URL).
24
- - `user` — the authenticated user / actor identity (subject, email,
25
- connection). The `user` vs `anonymous` classification is always kept, but the
26
- identifying values are omitted when disabled.
24
+ - `user` — the authenticated user / actor identity (subject, email, connection).
25
+ The `user` vs `anonymous` classification is always kept, but the identifying
26
+ values are omitted when disabled.
27
27
  - `ipAddress` — the caller's IP address.
28
28
  - `geolocation` — the caller's country, region, and city.
29
29
 
@@ -87,7 +87,8 @@ export async function deleteAccount(
87
87
  The event object passed to `log()` supports the following fields. Only `type` is
88
88
  required.
89
89
 
90
- - `type` — the event type, in reverse-DNS form (e.g. `com.acme.account.deleted`).
90
+ - `type` — the event type, in reverse-DNS form (e.g.
91
+ `com.acme.account.deleted`).
91
92
  - `subject` — the primary entity the event is about.
92
93
  - `resources` — an array of `{ type, id, metadata? }` describing the resources
93
94
  the event affected.
@@ -95,9 +96,8 @@ required.
95
96
  - `data` — any additional structured data to attach to the event.
96
97
  - `actor` — override the automatically-derived actor
97
98
  (`{ sub, type, email, connection }`).
98
- - `country`, `region`, `city` — override the caller's geolocation. These
99
- default to the current request's location, so you normally don't need to set
100
- them.
99
+ - `country`, `region`, `city` — override the caller's geolocation. These default
100
+ to the current request's location, so you normally don't need to set them.
101
101
 
102
102
  Audit logging is best-effort: `log()` never throws and never blocks or fails the
103
103
  request, even if an event cannot be recorded.
@@ -134,4 +134,9 @@ pass, and the remaining fields are populated from the request context.
134
134
 
135
135
  ## Viewing Audit Logs
136
136
 
137
- In-portal viewing and retrieval of audit logs is coming soon.
137
+ Audit logs are available in the [Zuplo portal](https://portal.zuplo.com) under
138
+ your project's Audit Log service, where you can browse and search the events
139
+ recorded by this policy.
140
+
141
+ You can also query audit logs programmatically using the
142
+ [Zuplo API](https://zuplo.com/docs/api).
@@ -7,7 +7,7 @@
7
7
  "isPaidAddOn": false,
8
8
  "isEnterprise": true,
9
9
  "isInternal": false,
10
- "isBeta": true,
10
+ "isBeta": false,
11
11
  "isHidden": false,
12
12
  "requiresAI": false,
13
13
  "products": ["api-gateway"],
@@ -7,7 +7,7 @@
7
7
  "isPaidAddOn": false,
8
8
  "isEnterprise": true,
9
9
  "isInternal": false,
10
- "isBeta": true,
10
+ "isBeta": false,
11
11
  "isHidden": false,
12
12
  "requiresAI": false,
13
13
  "products": ["api-gateway"],
@@ -42,8 +42,8 @@
42
42
  },
43
43
  "frontendApiUrl": {
44
44
  "type": "string",
45
- "examples": ["https://sensible-skunk-49.clerk.accounts.dev"],
46
- "description": "Your Clerk frontend api url, i.e. `https://sensible-skunk-49.clerk.accounts.dev`. Can be found in the Clerk portal: https://dashboard.clerk.com/last-active?path=api-keys."
45
+ "examples": ["https://verb-noun-00.clerk.accounts.dev"],
46
+ "description": "Your Clerk Frontend API URL, i.e. `https://verb-noun-00.clerk.accounts.dev`. Can be found in the Clerk portal: https://dashboard.clerk.com/last-active?path=api-keys."
47
47
  },
48
48
  "oAuthResourceMetadataEnabled": {
49
49
  "type": "boolean",
@@ -59,7 +59,7 @@
59
59
  "module": "$import(@zuplo/runtime)",
60
60
  "options": {
61
61
  "allowUnauthenticatedRequests": false,
62
- "frontendApiUrl": "https://sensible-skunk-49.clerk.accounts.dev",
62
+ "frontendApiUrl": "https://verb-noun-00.clerk.accounts.dev",
63
63
  "oAuthResourceMetadataEnabled": false
64
64
  }
65
65
  }
@@ -100,7 +100,7 @@
100
100
  {
101
101
  "type": "object",
102
102
  "additionalProperties": false,
103
- "required": ["enabled", "trustedIssuers"],
103
+ "required": ["enabled"],
104
104
  "properties": {
105
105
  "enabled": {
106
106
  "const": true,
@@ -109,21 +109,24 @@
109
109
  "trustedIssuers": {
110
110
  "type": "array",
111
111
  "minItems": 1,
112
- "description": "Trusted ID-JAG issuers. These values are never published in OAuth metadata.",
112
+ "description": "Trusted ID-JAG issuers. These values are never published in OAuth metadata. Omit to trust this policy's browser-login IdP.",
113
113
  "items": {
114
114
  "type": "object",
115
115
  "additionalProperties": false,
116
- "required": ["issuer", "jwksUrl"],
116
+ "dependentRequired": {
117
+ "issuer": ["jwksUrl"],
118
+ "jwksUrl": ["issuer"]
119
+ },
117
120
  "properties": {
118
121
  "issuer": {
119
122
  "type": "string",
120
123
  "format": "uri",
121
- "description": "Exact issuer URL expected in the ID-JAG iss claim."
124
+ "description": "Exact issuer URL expected in the ID-JAG iss claim. Provide together with jwksUrl, or omit both to default to this policy's browser-login IdP."
122
125
  },
123
126
  "jwksUrl": {
124
127
  "type": "string",
125
128
  "format": "uri",
126
- "description": "JWKS URL used to verify ID-JAG signatures from this issuer."
129
+ "description": "JWKS URL used to verify ID-JAG signatures from this issuer. Provide together with issuer, or omit both to default to this policy's browser-login IdP."
127
130
  },
128
131
  "expectedClientIds": {
129
132
  "type": "array",
@@ -82,6 +82,84 @@
82
82
  }
83
83
  }
84
84
  },
85
+ "idJag": {
86
+ "description": "Optional Identity Assertion JWT Authorization Grant (ID-JAG / XAA) support for the gateway token endpoint.",
87
+ "oneOf": [
88
+ {
89
+ "type": "object",
90
+ "additionalProperties": false,
91
+ "required": ["enabled"],
92
+ "properties": {
93
+ "enabled": {
94
+ "const": false,
95
+ "description": "Disable ID-JAG support."
96
+ }
97
+ }
98
+ },
99
+ {
100
+ "type": "object",
101
+ "additionalProperties": false,
102
+ "required": ["enabled"],
103
+ "properties": {
104
+ "enabled": {
105
+ "const": true,
106
+ "description": "Enable ID-JAG support."
107
+ },
108
+ "trustedIssuers": {
109
+ "type": "array",
110
+ "minItems": 1,
111
+ "description": "Trusted ID-JAG issuers. These values are never published in OAuth metadata. Omit to trust this policy's browser-login IdP.",
112
+ "items": {
113
+ "type": "object",
114
+ "additionalProperties": false,
115
+ "dependentRequired": {
116
+ "issuer": ["jwksUrl"],
117
+ "jwksUrl": ["issuer"]
118
+ },
119
+ "properties": {
120
+ "issuer": {
121
+ "type": "string",
122
+ "format": "uri",
123
+ "description": "Exact issuer URL expected in the ID-JAG iss claim. Provide together with jwksUrl, or omit both to default to this policy's browser-login IdP."
124
+ },
125
+ "jwksUrl": {
126
+ "type": "string",
127
+ "format": "uri",
128
+ "description": "JWKS URL used to verify ID-JAG signatures from this issuer. Provide together with issuer, or omit both to default to this policy's browser-login IdP."
129
+ },
130
+ "expectedClientIds": {
131
+ "type": "array",
132
+ "items": {
133
+ "type": "string",
134
+ "minLength": 1
135
+ },
136
+ "description": "Optional allow-list of client IDs accepted from this issuer. The ID-JAG client_id must still match the authenticated token-endpoint client."
137
+ },
138
+ "subjectMapping": {
139
+ "type": "string",
140
+ "enum": [
141
+ "iss_prefix",
142
+ "iss_tenant_prefix",
143
+ "sub_id_only"
144
+ ],
145
+ "default": "iss_prefix",
146
+ "description": "How the ID-JAG subject is mapped into the gateway subject ID."
147
+ }
148
+ }
149
+ }
150
+ },
151
+ "authorizationDetailsTypesAllowed": {
152
+ "type": "array",
153
+ "items": {
154
+ "type": "string",
155
+ "minLength": 1
156
+ },
157
+ "description": "Optional allow-list of RFC 9396 authorization_details type values accepted from ID-JAGs."
158
+ }
159
+ }
160
+ }
161
+ ]
162
+ },
85
163
  "browserLoginOverrides": {
86
164
  "type": "object",
87
165
  "description": "Optional overrides for the derived browser-login settings.",
@@ -98,6 +98,84 @@
98
98
  }
99
99
  }
100
100
  },
101
+ "idJag": {
102
+ "description": "Optional Identity Assertion JWT Authorization Grant (ID-JAG / XAA) support for the gateway token endpoint.",
103
+ "oneOf": [
104
+ {
105
+ "type": "object",
106
+ "additionalProperties": false,
107
+ "required": ["enabled"],
108
+ "properties": {
109
+ "enabled": {
110
+ "const": false,
111
+ "description": "Disable ID-JAG support."
112
+ }
113
+ }
114
+ },
115
+ {
116
+ "type": "object",
117
+ "additionalProperties": false,
118
+ "required": ["enabled"],
119
+ "properties": {
120
+ "enabled": {
121
+ "const": true,
122
+ "description": "Enable ID-JAG support."
123
+ },
124
+ "trustedIssuers": {
125
+ "type": "array",
126
+ "minItems": 1,
127
+ "description": "Trusted ID-JAG issuers. These values are never published in OAuth metadata. Omit to trust this policy's browser-login IdP.",
128
+ "items": {
129
+ "type": "object",
130
+ "additionalProperties": false,
131
+ "dependentRequired": {
132
+ "issuer": ["jwksUrl"],
133
+ "jwksUrl": ["issuer"]
134
+ },
135
+ "properties": {
136
+ "issuer": {
137
+ "type": "string",
138
+ "format": "uri",
139
+ "description": "Exact issuer URL expected in the ID-JAG iss claim. Provide together with jwksUrl, or omit both to default to this policy's browser-login IdP."
140
+ },
141
+ "jwksUrl": {
142
+ "type": "string",
143
+ "format": "uri",
144
+ "description": "JWKS URL used to verify ID-JAG signatures from this issuer. Provide together with issuer, or omit both to default to this policy's browser-login IdP."
145
+ },
146
+ "expectedClientIds": {
147
+ "type": "array",
148
+ "items": {
149
+ "type": "string",
150
+ "minLength": 1
151
+ },
152
+ "description": "Optional allow-list of client IDs accepted from this issuer. The ID-JAG client_id must still match the authenticated token-endpoint client."
153
+ },
154
+ "subjectMapping": {
155
+ "type": "string",
156
+ "enum": [
157
+ "iss_prefix",
158
+ "iss_tenant_prefix",
159
+ "sub_id_only"
160
+ ],
161
+ "default": "iss_prefix",
162
+ "description": "How the ID-JAG subject is mapped into the gateway subject ID."
163
+ }
164
+ }
165
+ }
166
+ },
167
+ "authorizationDetailsTypesAllowed": {
168
+ "type": "array",
169
+ "items": {
170
+ "type": "string",
171
+ "minLength": 1
172
+ },
173
+ "description": "Optional allow-list of RFC 9396 authorization_details type values accepted from ID-JAGs."
174
+ }
175
+ }
176
+ }
177
+ ]
178
+ },
101
179
  "browserLoginOverrides": {
102
180
  "type": "object",
103
181
  "description": "Optional overrides for the derived browser-login settings.",