zuplo 6.71.6 → 6.71.8

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,153 @@
1
+ ---
2
+ title: Reading Subscription Data
3
+ sidebar_label: Subscription Data
4
+ ---
5
+
6
+ When the `MonetizationInboundPolicy` authenticates a request, it looks up the
7
+ caller's subscription — their plan, entitlements, payment status, and billing
8
+ dates — and stores it on the request context. Read that data from your own code
9
+ with the static `MonetizationInboundPolicy.getSubscriptionData` method to make
10
+ decisions, personalize responses, or log which plan a request ran on.
11
+
12
+ ## Where you can call it
13
+
14
+ `getSubscriptionData` returns data that the monetization policy puts on the
15
+ context, so it only returns a value **after** the `monetization-inbound` policy
16
+ has run. Call it from:
17
+
18
+ - A **custom code inbound policy** placed _after_ `monetization-inbound` in the
19
+ route's inbound pipeline.
20
+ - The **route handler**, which always runs after inbound policies.
21
+
22
+ On a route without the monetization policy — or in a policy that runs before it
23
+ — the method returns `undefined`. Always handle that case.
24
+
25
+ :::note
26
+
27
+ The `monetization-inbound` policy must come before any policy that reads the
28
+ subscription. If your policy runs first, the subscription data isn't on the
29
+ context yet. See
30
+ [pipeline ordering](./monetization-policy.md#pipeline-ordering).
31
+
32
+ :::
33
+
34
+ ## Basic usage
35
+
36
+ ```ts
37
+ import {
38
+ MonetizationInboundPolicy,
39
+ HttpProblems,
40
+ ZuploContext,
41
+ ZuploRequest,
42
+ } from "@zuplo/runtime";
43
+
44
+ export default async function (request: ZuploRequest, context: ZuploContext) {
45
+ const subscription = MonetizationInboundPolicy.getSubscriptionData(context);
46
+
47
+ if (!subscription) {
48
+ return HttpProblems.forbidden(request, context, {
49
+ detail: "No active subscription",
50
+ });
51
+ }
52
+
53
+ context.log.info(`Request on plan: ${subscription.plan.key}`);
54
+ return request;
55
+ }
56
+ ```
57
+
58
+ ## The subscription object
59
+
60
+ `getSubscriptionData` returns a `MonetizationSubscription`. The fields you reach
61
+ for most are the plan and the entitlements map:
62
+
63
+ ```ts
64
+ interface MonetizationSubscription {
65
+ id: string;
66
+ customerId: string;
67
+ name: string;
68
+ status: string;
69
+ currency: string;
70
+
71
+ plan: {
72
+ id: string;
73
+ name: string;
74
+ key: string; // Stable identifier — switch on this in code
75
+ version: number;
76
+ description?: string;
77
+ };
78
+
79
+ // Keyed by meter or feature key
80
+ entitlements: Record<
81
+ string,
82
+ {
83
+ balance: number; // Remaining allowance this period
84
+ hasAccess: boolean; // false when no access or quota spent
85
+ overage: number; // Usage beyond the included allowance
86
+ usage: number; // Consumed this period
87
+ }
88
+ >;
89
+
90
+ paymentStatus?: {
91
+ status: "paid" | "not_required" | "pending" | "failed" | "uncollectible";
92
+ isFirstPayment: boolean;
93
+ lastPaymentFailedAt?: string;
94
+ lastPaymentSucceededAt?: string;
95
+ };
96
+
97
+ billingCadence: string; // ISO 8601 duration, e.g. "P1M" for monthly
98
+ billingAnchor: string;
99
+ nextBillingDate: string;
100
+ activeFrom: string;
101
+ activeTo?: string;
102
+
103
+ maxPaymentOverdueDays: number;
104
+ accessBlocked?: boolean;
105
+ createdAt: string;
106
+ updatedAt: string;
107
+ }
108
+ ```
109
+
110
+ Switch on `plan.key` rather than `plan.name` in your logic — the key is a stable
111
+ identifier, while the name is a display label that can change.
112
+
113
+ ## Reading entitlements
114
+
115
+ Each entry in `entitlements` describes one metered feature or static feature on
116
+ the subscription. The key is the meter or feature key; the value reports the
117
+ caller's standing against it:
118
+
119
+ ```ts
120
+ const subscription = MonetizationInboundPolicy.getSubscriptionData(context);
121
+
122
+ const apiCalls = subscription?.entitlements["api_requests"];
123
+ if (apiCalls) {
124
+ context.log.info(
125
+ `api_requests — used ${apiCalls.usage}, ${apiCalls.balance} remaining`,
126
+ );
127
+ }
128
+ ```
129
+
130
+ - `hasAccess` is the quickest check for "can this caller use this feature" —
131
+ it's `false` when the plan doesn't include the feature or the quota has run
132
+ out.
133
+ - `balance` is the remaining allowance. A balance of `0` or less means no
134
+ allowance remains.
135
+ - `usage` and `overage` report consumption this billing period.
136
+
137
+ ## Caveats
138
+
139
+ - **Returns `undefined`** when the monetization policy hasn't run. Guard every
140
+ call.
141
+ - **The policy caches the data.** Subscription and entitlement data is cached
142
+ for up to `cacheTtlSeconds` (60 seconds minimum), so `balance`, `usage`, and
143
+ `overage` can lag real-time consumption by the length of the cache window.
144
+ Treat them as recent, not exact.
145
+
146
+ ## Next steps
147
+
148
+ - [Programmatic Monetization](./programmatic-monetization.md) — gate operations
149
+ by plan and meter requests based on the response.
150
+ - [Dynamic Metering](./dynamic-metering.md) — set meter values at runtime from
151
+ code.
152
+ - [Monetization Policy Reference](./monetization-policy.md) — every policy
153
+ configuration option.
@@ -0,0 +1,142 @@
1
+ ---
2
+ title: OpenAPI Format Validation Warnings in Local Development
3
+ sidebar_label: Format Validation Warnings
4
+ description:
5
+ Understand the "unknown format ... ignored" warnings the Zuplo CLI prints
6
+ during local development, why they appear, and why they are safe to ignore.
7
+ tags:
8
+ - openapi
9
+ - local-development
10
+ - validation
11
+ ---
12
+
13
+ When you run a Zuplo project locally with `npm run dev` (or `zuplo dev`), the
14
+ console may print one or more warnings like this:
15
+
16
+ ```text
17
+ unknown format "date-time" ignored in schema at path "#/properties/createdAt"
18
+ ```
19
+
20
+ These warnings are informational. They do not stop the development server, fail
21
+ schema validation, or change how your gateway behaves once deployed. This page
22
+ explains what the warning means and what, if anything, to do about it.
23
+
24
+ :::tip
25
+
26
+ **Short answer: the warnings are safe to ignore.** They report that a `format`
27
+ keyword in your OpenAPI document is not being actively checked — the field is
28
+ still validated against its `type` and every other constraint you defined.
29
+
30
+ :::
31
+
32
+ ## What the warning means
33
+
34
+ Zuplo validates requests against your OpenAPI schema using
35
+ [Ajv](https://ajv.js.org/), a standard JSON Schema validator. In JSON Schema and
36
+ OpenAPI, the
37
+ [`format` keyword](https://json-schema.org/understanding-json-schema/reference/string#format)
38
+ (for example `date-time`, `email`, or `uuid`) is an _annotation_. A validator
39
+ only enforces a format if it has a validator registered for that specific
40
+ format. For any format it does not recognize, the standard behavior is to skip
41
+ the format check and log a message like the one above.
42
+
43
+ When you see `unknown format "date-time" ignored in schema at path "…"`, it
44
+ means:
45
+
46
+ - The validator found a `format: "date-time"` (or similar) in your schema.
47
+ - It has no registered check for that format in local development, so it
48
+ **ignores the format** and moves on.
49
+ - The field is **still validated** against its `type` and any other keywords you
50
+ set, such as `pattern`, `enum`, `minimum`, `maxLength`, or `required`.
51
+
52
+ The `path` in the message (for example `#/properties/createdAt`, or a path or
53
+ query parameter location) points to where the format appears in the schema, so
54
+ you can locate it.
55
+
56
+ ## Are the warnings safe to ignore?
57
+
58
+ Yes. The warning is purely informational. It does **not**:
59
+
60
+ - Stop or crash the local development server.
61
+ - Cause a build or deployment to fail.
62
+ - Reject any request, or change the response your API returns.
63
+ - Change validation behavior in deployed environments.
64
+
65
+ Type checking and every other constraint in your schema continue to work exactly
66
+ as written. An enforced `format` validates the _shape_ of a value — for example,
67
+ that a string looks like an RFC 3339 date-time. When a format is ignored, you
68
+ lose only that one extra check; the field's `type` and all other constraints are
69
+ unaffected.
70
+
71
+ ## Why some formats warn and others don't
72
+
73
+ You may notice the warning for some formats but not others, and on some fields
74
+ but not others. A few things drive this:
75
+
76
+ - **`format` is advisory in JSON Schema.** Validators are free to enforce only
77
+ the formats they choose to register. Which formats are actively checked is an
78
+ internal detail of the validator and can differ between CLI versions, so treat
79
+ the set as subject to change rather than a fixed contract.
80
+ - **Path and query parameters are validated separately from request bodies.**
81
+ Parameter schemas and body schemas are generally compiled independently, so
82
+ the same `format` can produce a warning in one place but not the other.
83
+
84
+ Because the warning is harmless, you do not need to determine exactly which
85
+ formats are checked. The guidance below applies to any format that warns.
86
+
87
+ ## How to remove the warnings
88
+
89
+ You have two options, depending on whether you rely on that format for
90
+ validation.
91
+
92
+ **Option 1 — Leave the `format` keyword in place (recommended).** Keeping
93
+ `format` annotations is good practice: they document intent, drive code
94
+ generation and the developer portal, and are useful to consumers of your API
95
+ even when the gateway does not enforce them. The warning is the only cost, and
96
+ it is cosmetic.
97
+
98
+ **Option 2 — Enforce the value with a constraint that _is_ checked.** If you
99
+ want the gateway to actively reject malformed values, replace or supplement the
100
+ `format` with explicit constraints that the validator always enforces, such as
101
+ `pattern`, `enum`, `minLength`/`maxLength`, or `minimum`/`maximum`. For example,
102
+ to enforce a date-time-like string with a regular expression instead of relying
103
+ on `format`:
104
+
105
+ ```json
106
+ {
107
+ "createdAt": {
108
+ "type": "string",
109
+ "format": "date-time",
110
+ "pattern": "^\\d{4}-\\d{2}-\\d{2}T\\d{2}:\\d{2}:\\d{2}(\\.\\d+)?(Z|[+-]\\d{2}:\\d{2})$"
111
+ }
112
+ }
113
+ ```
114
+
115
+ Here `format` stays for documentation, and `pattern` does the actual
116
+ enforcement. The regular expression above is an illustrative RFC 3339-style
117
+ example, not a Zuplo-mandated pattern — adjust it to match the values you
118
+ expect. The warning may still appear for the ignored `format`, but the value is
119
+ now strictly validated.
120
+
121
+ :::caution
122
+
123
+ The [Request Validation policy](../policies/request-validation-inbound.mdx)
124
+ options control _what_ is validated (`validateBody`, `validateQueryParameters`,
125
+ `validatePathParameters`, `validateHeaders`) and how failures are handled, but
126
+ they do not let you register additional formats or silence individual format
127
+ warnings. To guarantee a value's shape, use enforced constraints like `pattern`
128
+ as shown above.
129
+
130
+ :::
131
+
132
+ ## Related
133
+
134
+ - [Request Validation Policy](../policies/request-validation-inbound.mdx) —
135
+ validate request bodies, query parameters, path parameters, and headers
136
+ against your OpenAPI schema.
137
+ - [Schema Validation Failed (SCHEMA_VALIDATION_FAILED)](../errors/schema-validation-failed.mdx)
138
+ — the runtime error returned when a request does not pass schema validation.
139
+ - [OpenAPI Support in Zuplo](./openapi.mdx) — how Zuplo uses your OpenAPI
140
+ document to configure the gateway.
141
+ - [Local Development](./local-development.mdx) — run and test your gateway
142
+ locally with the Zuplo CLI.
@@ -0,0 +1,222 @@
1
+ ---
2
+ title: Troubleshooting Stuck Deployments and Git Sync Errors
3
+ sidebar_label: Troubleshooting Deployments
4
+ description:
5
+ Diagnose Zuplo deployments that hang at "Deploying api" or "Building Developer
6
+ Portal" and fix Git source-control sync errors such as Bitbucket 410 Gone
7
+ responses on branch retrieval.
8
+ ---
9
+
10
+ When a deploy seems to hang at `Deploying api…` or `Building Developer Portal…`,
11
+ or your Git provider stops returning branches with a `Bad Request` or `410 Gone`
12
+ error, the cause is usually one of a few known issues. This guide helps you tell
13
+ a genuinely stuck deploy from a slow-but-progressing one, fix Git source-control
14
+ sync failures, and gather the right details before contacting support.
15
+
16
+ ## How a Zuplo deploy progresses
17
+
18
+ Every deploy, whether triggered by a Git push, the Zuplo CLI, or a save in the
19
+ Portal, runs through two stages in order:
20
+
21
+ 1. **`Deploying api…`**: Zuplo builds your gateway configuration (routes,
22
+ policies, and modules) and rolls it out to the edge.
23
+ 2. **`Building Developer Portal…`**: Zuplo builds the Developer Portal site from
24
+ your OpenAPI document and portal configuration.
25
+
26
+ Each stage produces its own build logs. Zuplo separates logs by stage: `api` for
27
+ the gateway build and `dev-portal` for the Developer Portal build. Knowing which
28
+ stage a deploy stalled in tells you where to look.
29
+
30
+ :::note
31
+
32
+ A deploy can finish the `api` stage successfully and still be working on the
33
+ `dev-portal` stage. If your gateway is already serving traffic but the deploy
34
+ status hasn't flipped to complete, the Developer Portal build is the most likely
35
+ place it's still working. See
36
+ [The Developer Portal build never finishes](#the-developer-portal-build-never-finishes).
37
+
38
+ :::
39
+
40
+ ## Is the deploy stuck, or still working?
41
+
42
+ A deploy that looks frozen in the terminal is often still running on Zuplo's
43
+ side. The Zuplo CLI doesn't run the build itself. It starts the deploy and then
44
+ _polls_ for the result. The build continues on the server even if the CLI stops
45
+ waiting.
46
+
47
+ ### Confirm the server-side status first
48
+
49
+ Before assuming a deploy failed, check whether it actually completed:
50
+
51
+ 1. Open your [project](https://portal.zuplo.com/+/account/project/) in the Zuplo
52
+ Portal.
53
+ 2. Check the environment you deployed to. If the build finished, the environment
54
+ shows the new deployment and its URL responds to requests.
55
+ 3. Send a request to the environment URL (or its
56
+ [health check route](./health-checks.mdx), if you have one) to confirm the
57
+ gateway is live.
58
+
59
+ If the environment is updated and serving traffic, the deploy succeeded. The CLI
60
+ simply stopped waiting before the build reported back.
61
+
62
+ :::tip
63
+
64
+ The CLI prints `Deployed to https://...` on success. If you never saw that line
65
+ but the Portal shows the environment updated, the deploy completed after the CLI
66
+ timed out. Capture the URL from the Portal rather than constructing it from the
67
+ branch name. The hostname uses a normalized, truncated form of the environment
68
+ name plus a unique identifier.
69
+
70
+ :::
71
+
72
+ ### Extend the CLI polling timeout
73
+
74
+ By default the CLI polls every second for up to 250 attempts, a little over four
75
+ minutes. Large projects can take longer to build, and when the CLI's poll budget
76
+ runs out it stops waiting even though the deploy keeps running on the server.
77
+
78
+ Increase the timeout with the `POLL_INTERVAL` and `MAX_POLL_RETRIES` environment
79
+ variables:
80
+
81
+ ```bash
82
+ # Poll every 5 seconds for up to 300 attempts (25 minutes)
83
+ POLL_INTERVAL=5000 MAX_POLL_RETRIES=300 zuplo deploy
84
+ ```
85
+
86
+ - **`POLL_INTERVAL`**: Milliseconds between polls. Default `1000` (1 second).
87
+ - **`MAX_POLL_RETRIES`**: Maximum number of polls before the CLI times out.
88
+ Default `250`.
89
+
90
+ For the full command reference, see [CLI: deploy](../cli/deploy.mdx).
91
+
92
+ :::caution
93
+
94
+ Raising the polling timeout only changes how long the CLI _waits_. It does not
95
+ make the build faster, and it does not fix a build that is genuinely failing. If
96
+ the deploy never completes server-side no matter how long you wait, treat it as
97
+ a failed build and read the logs for the stage that stalled.
98
+
99
+ :::
100
+
101
+ ## The Developer Portal build never finishes
102
+
103
+ If the gateway (`api` stage) deploys but the overall deploy hangs at
104
+ `Building Developer Portal…`, the problem is in the Developer Portal build, not
105
+ your routes or policies.
106
+
107
+ Common causes:
108
+
109
+ - **Invalid OpenAPI document**: The portal is generated from your OpenAPI
110
+ document. A malformed `routes.oas.json`, an unresolved `$ref`, or invalid
111
+ schema can stall or fail the portal build. Validate your OpenAPI document and
112
+ fix any errors.
113
+ - **A legacy `config/dev-portal.json` file**: Projects migrated from the old
114
+ Developer Portal can carry a stale `config/dev-portal.json` that breaks the
115
+ build. See the [Dev Portal Migration Guide](../dev-portal/migration.mdx) for
116
+ the exact cleanup steps.
117
+ - **Custom portal configuration errors**: Errors in your `zudoku.config.tsx` (or
118
+ other portal configuration) can prevent the site from building.
119
+
120
+ Read the `dev-portal` stage build logs to see the specific error, then redeploy
121
+ after fixing it.
122
+
123
+ ## Git source-control sync errors
124
+
125
+ Zuplo connects to GitHub, GitLab, Bitbucket, and Azure DevOps for source
126
+ control. The integration pushes and pulls code between the Portal and your
127
+ repository, and it lists branches so you can map them to environments. When that
128
+ authorization breaks, branch retrieval fails, often with a `Bad Request` or
129
+ `410 Gone` error.
130
+
131
+ ### Why branch retrieval returns `Bad Request` or `410 Gone`
132
+
133
+ These errors come from the Git provider, not from Zuplo, and they almost always
134
+ mean the connection is no longer authorized:
135
+
136
+ - The OAuth authorization Zuplo uses to reach the provider has **expired or been
137
+ revoked**.
138
+ - The repository was **renamed or moved**, which breaks the existing connection.
139
+ - The Git app was **uninstalled** or lost access to the repository in the
140
+ provider's settings.
141
+
142
+ `410 Gone` in particular signals that the resource Zuplo asked for (the branch
143
+ list) is no longer available at that location, typically because the
144
+ authorization or repository link behind it is stale.
145
+
146
+ ### Reconnect the integration
147
+
148
+ To restore branch sync, re-authorize the connection:
149
+
150
+ 1. Open your
151
+ [project settings](https://portal.zuplo.com/+/account/project/settings/general)
152
+ in the Zuplo Portal and select **Source Control**.
153
+ 2. Disconnect the current repository connection.
154
+ 3. Reconnect and complete the provider's authorization flow again, granting
155
+ access to the repository that holds your Zuplo project.
156
+
157
+ After reconnecting, retrieving branches should succeed again.
158
+
159
+ :::caution
160
+
161
+ Renaming a repository breaks the Zuplo connection. If you renamed or moved the
162
+ repository, disconnect and reconnect to restore the link. See
163
+ [Rename or Move Project](./rename-or-move-project.mdx) for details.
164
+
165
+ :::
166
+
167
+ ### Bitbucket-specific notes
168
+
169
+ Bitbucket integration is available on
170
+ [enterprise plans](https://zuplo.com/pricing) and provides push/pull source
171
+ control without automatic deployments. You deploy with the Zuplo CLI through
172
+ [Bitbucket Pipelines](./custom-ci-cd-bitbucket.mdx).
173
+
174
+ If reconnecting from the Portal doesn't clear the sync error:
175
+
176
+ - **Confirm Bitbucket is still enabled for your account.** For
177
+ [bitbucket.org](https://bitbucket.org), Zuplo support enables the integration.
178
+ Contact [support@zuplo.com](mailto:support@zuplo.com) with your Bitbucket
179
+ Workspace ID (found on your Workspace Settings page).
180
+ - **For self-hosted Bitbucket, check the OAuth app.** If the OAuth app's client
181
+ secret was rotated or its callback URL or permissions changed, branch
182
+ retrieval fails until the app is reconfigured. The callback URL must be
183
+ `https://portal.zuplo.com` and the app must grant the `repo`, `user`, and
184
+ `read:org` permissions. See
185
+ [Bitbucket Setup](./source-control-setup-bitbucket.mdx).
186
+
187
+ ## Decision tree
188
+
189
+ Use this to route yourself to the right fix:
190
+
191
+ | Symptom | Most likely cause | First action |
192
+ | ---------------------------------------------------- | ----------------------------------------------- | ---------------------------------------------------------------------------------------------- |
193
+ | CLI hangs at `Deploying api…` then times out | Build took longer than the CLI's poll budget | Check the environment in the Portal; raise `MAX_POLL_RETRIES` |
194
+ | CLI reported timeout, but the environment is updated | Deploy completed after the CLI stopped waiting | None; capture the URL from the Portal |
195
+ | Deploy hangs at `Building Developer Portal…` | Developer Portal build error | Read the `dev-portal` build logs; validate OpenAPI; check for a stale `config/dev-portal.json` |
196
+ | Branch list fails with `Bad Request` or `410 Gone` | Git authorization expired, revoked, or stale | Reconnect the integration in **Source Control** settings |
197
+ | Bitbucket still fails after reconnecting | Account not enabled, or OAuth app misconfigured | Contact support with your Workspace ID; check the self-hosted OAuth app |
198
+
199
+ ## When to contact support
200
+
201
+ If you've worked through the relevant section above and the deploy or sync still
202
+ fails, contact [support@zuplo.com](mailto:support@zuplo.com). Include these
203
+ details so support can investigate without a round-trip:
204
+
205
+ - Your **account** and **project** names.
206
+ - The **environment** (branch) you're deploying to.
207
+ - The **stage** where it stalls (`api` or `dev-portal`) and the exact message
208
+ you see.
209
+ - For sync errors: your **Git provider**, the **repository**, and the exact
210
+ error text (for example, `410 Gone` on branch retrieval).
211
+ - The **approximate time** of the failed deploy, in UTC.
212
+
213
+ ## Next steps
214
+
215
+ - [Source Control & Deployments](./source-control.mdx): how source control and
216
+ deployments fit together across providers.
217
+ - [Branch-Based Deployments](./branch-based-deployments.mdx): how branches map
218
+ to environments and how environment URLs are named.
219
+ - [Deploying Zuplo from a Monorepo](./monorepo-deployment.mdx): CI/CD
220
+ configuration, schema validation, and health-check timeouts.
221
+ - [Troubleshooting (local development)](./local-development-troubleshooting.mdx):
222
+ local dev server, ports, and certificate issues.
@@ -177,6 +177,12 @@
177
177
  "type": "integer",
178
178
  "minimum": 1,
179
179
  "default": 28800
180
+ },
181
+ "pkce": {
182
+ "type": "string",
183
+ "enum": ["S256", "none"],
184
+ "default": "none",
185
+ "description": "Whether to send S256 PKCE on the federated browser-login authorization request and replay the verifier at the token exchange. Defaults to \"none\". Set to \"S256\" when the identity provider mandates PKCE on the authorization-code flow."
180
186
  }
181
187
  }
182
188
  }
@@ -191,6 +197,7 @@
191
197
  "audience": "https://gateway.example.com",
192
198
  "auth0Domain": "my-tenant.us.auth0.com",
193
199
  "browserLoginOverrides": {
200
+ "pkce": "none",
194
201
  "remoteTimeoutMs": 10000,
195
202
  "sessionTtlSeconds": 28800,
196
203
  "stateTtlSeconds": 900
@@ -117,6 +117,12 @@
117
117
  "type": "integer",
118
118
  "minimum": 1,
119
119
  "default": 28800
120
+ },
121
+ "pkce": {
122
+ "type": "string",
123
+ "enum": ["S256", "none"],
124
+ "default": "none",
125
+ "description": "Whether to send S256 PKCE on the federated browser-login authorization request and replay the verifier at the token exchange. Defaults to \"none\". Set to \"S256\" when the identity provider mandates PKCE on the authorization-code flow."
120
126
  }
121
127
  }
122
128
  }
@@ -130,6 +136,7 @@
130
136
  "options": {
131
137
  "awsRegion": "us-east-1",
132
138
  "browserLoginOverrides": {
139
+ "pkce": "none",
133
140
  "remoteTimeoutMs": 10000,
134
141
  "sessionTtlSeconds": 28800,
135
142
  "stateTtlSeconds": 900
@@ -98,6 +98,12 @@
98
98
  "type": "integer",
99
99
  "minimum": 1,
100
100
  "default": 28800
101
+ },
102
+ "pkce": {
103
+ "type": "string",
104
+ "enum": ["S256", "none"],
105
+ "default": "none",
106
+ "description": "Whether to send S256 PKCE on the federated browser-login authorization request and replay the verifier at the token exchange. Defaults to \"none\". Set to \"S256\" when the identity provider mandates PKCE on the authorization-code flow."
101
107
  }
102
108
  }
103
109
  }
@@ -110,6 +116,7 @@
110
116
  "module": "$import(@zuplo/runtime)",
111
117
  "options": {
112
118
  "browserLoginOverrides": {
119
+ "pkce": "none",
113
120
  "remoteTimeoutMs": 10000,
114
121
  "sessionTtlSeconds": 28800,
115
122
  "stateTtlSeconds": 900
@@ -93,6 +93,12 @@
93
93
  "type": "integer",
94
94
  "minimum": 1,
95
95
  "default": 28800
96
+ },
97
+ "pkce": {
98
+ "type": "string",
99
+ "enum": ["S256", "none"],
100
+ "default": "none",
101
+ "description": "Whether to send S256 PKCE on the federated browser-login authorization request and replay the verifier at the token exchange. Defaults to \"none\". Set to \"S256\" when the identity provider mandates PKCE on the authorization-code flow."
96
102
  }
97
103
  }
98
104
  }
@@ -105,6 +111,7 @@
105
111
  "module": "$import(@zuplo/runtime)",
106
112
  "options": {
107
113
  "browserLoginOverrides": {
114
+ "pkce": "none",
108
115
  "remoteTimeoutMs": 10000,
109
116
  "sessionTtlSeconds": 28800,
110
117
  "stateTtlSeconds": 900
@@ -106,6 +106,12 @@
106
106
  "type": "integer",
107
107
  "minimum": 1,
108
108
  "default": 28800
109
+ },
110
+ "pkce": {
111
+ "type": "string",
112
+ "enum": ["S256", "none"],
113
+ "default": "none",
114
+ "description": "Whether to send S256 PKCE on the federated browser-login authorization request and replay the verifier at the token exchange. Defaults to \"none\". Set to \"S256\" when the identity provider mandates PKCE on the authorization-code flow."
109
115
  }
110
116
  }
111
117
  }
@@ -118,6 +124,7 @@
118
124
  "module": "$import(@zuplo/runtime)",
119
125
  "options": {
120
126
  "browserLoginOverrides": {
127
+ "pkce": "none",
121
128
  "remoteTimeoutMs": 10000,
122
129
  "sessionTtlSeconds": 28800,
123
130
  "stateTtlSeconds": 900
@@ -98,6 +98,12 @@
98
98
  "type": "integer",
99
99
  "minimum": 1,
100
100
  "default": 28800
101
+ },
102
+ "pkce": {
103
+ "type": "string",
104
+ "enum": ["S256", "none"],
105
+ "default": "none",
106
+ "description": "Whether to send S256 PKCE on the federated browser-login authorization request and replay the verifier at the token exchange. Defaults to \"none\". Set to \"S256\" when the identity provider mandates PKCE on the authorization-code flow."
101
107
  }
102
108
  }
103
109
  }
@@ -110,6 +116,7 @@
110
116
  "module": "$import(@zuplo/runtime)",
111
117
  "options": {
112
118
  "browserLoginOverrides": {
119
+ "pkce": "none",
113
120
  "remoteTimeoutMs": 10000,
114
121
  "sessionTtlSeconds": 28800,
115
122
  "stateTtlSeconds": 900
@@ -98,6 +98,12 @@
98
98
  "type": "string",
99
99
  "description": "Optional audience parameter for the IdP authorization request (Auth0-style API audiences)."
100
100
  },
101
+ "pkce": {
102
+ "type": "string",
103
+ "enum": ["S256", "none"],
104
+ "default": "none",
105
+ "description": "Whether to send S256 PKCE on the federated browser-login authorization request and replay the verifier at the token exchange. Defaults to \"none\". Set to \"S256\" when the identity provider mandates PKCE on the authorization-code flow (e.g. OAuth 2.1 IdPs, hardened Okta/Entra tenants). Leave as \"none\" for IdPs that may reject unexpected PKCE parameters."
106
+ },
101
107
  "remoteTimeoutMs": {
102
108
  "type": "integer",
103
109
  "minimum": 1,
@@ -227,6 +233,7 @@
227
233
  "options": {
228
234
  "browserLogin": {
229
235
  "clientSecret": "$env(MCP_OAUTH_CLIENT_SECRET)",
236
+ "pkce": "none",
230
237
  "remoteTimeoutMs": 10000,
231
238
  "scope": "openid profile email",
232
239
  "sessionTtlSeconds": 28800,