zuplo 7.7.16 → 7.8.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.
Files changed (39) hide show
  1. package/docs/ai-gateway/bedrock-runtime.mdx +317 -0
  2. package/docs/ai-gateway/providers.mdx +30 -0
  3. package/docs/ai-gateway/universal-api.mdx +30 -0
  4. package/docs/ai-gateway/usage-limits.mdx +34 -0
  5. package/docs/dev-portal/zudoku/components/stepper.mdx +34 -1
  6. package/docs/dev-portal/zudoku/configuration/llms.md +4 -0
  7. package/docs/policies/ai-gateway-auth-v2-inbound/doc.md +5 -2
  8. package/docs/policies/ai-gateway-configuration-executor-v2-inbound/doc.md +26 -2
  9. package/docs/policies/ai-gateway-configuration-loader-v2-inbound/doc.md +0 -2
  10. package/docs/policies/ai-gateway-dlp-inbound/schema.json +34 -10
  11. package/docs/policies/ai-gateway-fallback-model-v2-inbound/doc.md +0 -2
  12. package/docs/policies/ai-gateway-metering-v2-inbound/doc.md +0 -2
  13. package/docs/policies/ai-gateway-model-filtering-v2-inbound/doc.md +0 -2
  14. package/docs/policies/ai-gateway-semantic-cache-v2-inbound/doc.md +0 -2
  15. package/docs/policies/ai-gateway-smart-router-inbound/doc.md +7 -2
  16. package/docs/policies/akamai-ai-firewall-v2-inbound/doc.md +0 -2
  17. package/docs/policies/auth0-jwt-auth-inbound/doc.md +1 -1
  18. package/docs/policies/comet-opik-tracing-v2-inbound/doc.md +0 -2
  19. package/docs/policies/galileo-tracing-v2-inbound/doc.md +0 -2
  20. package/docs/policies/mcp-auth0-oauth-inbound/doc.md +0 -2
  21. package/docs/policies/mcp-auth0-oauth-inbound/schema.json +2 -2
  22. package/docs/policies/mcp-clerk-oauth-inbound/doc.md +0 -2
  23. package/docs/policies/mcp-cognito-oauth-inbound/doc.md +0 -2
  24. package/docs/policies/mcp-entra-oauth-inbound/doc.md +0 -2
  25. package/docs/policies/mcp-google-oauth-inbound/doc.md +0 -2
  26. package/docs/policies/mcp-keycloak-oauth-inbound/doc.md +0 -2
  27. package/docs/policies/mcp-logto-oauth-inbound/doc.md +0 -2
  28. package/docs/policies/mcp-oauth-inbound/doc.md +0 -2
  29. package/docs/policies/mcp-oauth-inbound/schema.json +1 -1
  30. package/docs/policies/mcp-okta-oauth-inbound/doc.md +0 -2
  31. package/docs/policies/mcp-onelogin-oauth-inbound/doc.md +0 -2
  32. package/docs/policies/mcp-ping-oauth-inbound/doc.md +0 -2
  33. package/docs/policies/mcp-token-exchange-inbound/doc.md +48 -2
  34. package/docs/policies/mcp-token-exchange-inbound/schema.json +8 -0
  35. package/docs/policies/mcp-workos-oauth-inbound/doc.md +0 -2
  36. package/docs/policies/monetization-inbound/doc.md +10 -2
  37. package/docs/policies/propel-auth-jwt-inbound/doc.md +1 -1
  38. package/docs/policies/secret-masking-outbound/doc.md +1 -1
  39. package/package.json +5 -5
@@ -0,0 +1,317 @@
1
+ ---
2
+ title: Using Bedrock Runtime
3
+ sidebar_label: Bedrock Runtime
4
+ description:
5
+ Put the AI Gateway in front of Amazon Bedrock's native API without changing
6
+ your code. Point your AWS SDK client at your app and keep every call site.
7
+ ---
8
+
9
+ **Bedrock Runtime** is
10
+ [Amazon Bedrock's native API](https://docs.aws.amazon.com/bedrock/latest/APIReference/API_Operations_Amazon_Bedrock_Runtime.html)—the
11
+ one the AWS SDKs call when you use `bedrock-runtime` from `@aws-sdk/*`, `boto3`,
12
+ or the Go and Java SDKs. Adding it as a provider lets those clients keep working
13
+ exactly as they are, with the gateway in the path for authentication, model
14
+ filtering, usage metering, and cost tracking.
15
+
16
+ This provider exists for one job: **you change the client's configuration, not
17
+ your code.** Point the client's `endpoint` at your app's URL, give it the app's
18
+ API key instead of AWS credentials, and every `ConverseCommand`,
19
+ `InvokeModelCommand`, and streaming call you already wrote keeps running.
20
+
21
+ Requests reach your own AWS account on your own AWS billing, signed by the
22
+ gateway with an IAM key pair you configure once.
23
+
24
+ ## Bedrock Runtime or Bedrock Mantle?
25
+
26
+ Zuplo supports two Amazon Bedrock providers. Both reach your own AWS account—
27
+ what separates them is the API your client speaks.
28
+
29
+ | | Bedrock Runtime | [Bedrock Mantle](./bedrock-mantle.mdx) |
30
+ | ----------------- | ----------------------------------------------- | -------------------------------------- |
31
+ | API your app uses | Bedrock's native API | OpenAI- or Anthropic-shaped |
32
+ | Client | an AWS SDK | any OpenAI or Anthropic client |
33
+ | Gateway path | `/{app_id}/model/{modelId}/{operation}` | `/{app_id}/v1/...` |
34
+ | Credential | long-term IAM access key pair | long-term Bedrock API key (`ABSK`) |
35
+ | Best for | existing AWS SDK code you don't want to rewrite | new code, or one API across providers |
36
+
37
+ Choose **Bedrock Runtime** when you already have AWS SDK code. Choose **Bedrock
38
+ Mantle** when you want Bedrock models through the same
39
+ [Universal API](./universal-api.mdx) as every other provider.
40
+
41
+ The two need separate provider configurations even for the same AWS account: a
42
+ provider holds exactly one credential, and a Bedrock API key can't be used as an
43
+ IAM access key pair.
44
+
45
+ ## Supported operations
46
+
47
+ The gateway serves the four Bedrock Runtime operations at their AWS paths:
48
+
49
+ | Operation | Path | Streaming |
50
+ | ------------------------------- | ---------------------------------------------- | --------- |
51
+ | `Converse` | `/model/{modelId}/converse` | No |
52
+ | `ConverseStream` | `/model/{modelId}/converse-stream` | Yes |
53
+ | `InvokeModel` | `/model/{modelId}/invoke` | No |
54
+ | `InvokeModelWithResponseStream` | `/model/{modelId}/invoke-with-response-stream` | Yes |
55
+
56
+ Your request and response bodies pass through unchanged, so anything these
57
+ operations support works—tool use, guardrail configuration,
58
+ `additionalModelRequestFields`, and model-native `InvokeModel` bodies the
59
+ gateway has no knowledge of. Streaming responses keep Bedrock's
60
+ `application/vnd.amazon.eventstream` framing, so the SDK's own decoder reads
61
+ them as it always has.
62
+
63
+ Your request headers reach Bedrock as well, including the `x-amzn-bedrock-*`
64
+ headers and the `x-amz-*` ones your SDK sets. The gateway removes only what it
65
+ owns: the `Authorization` header carrying your app's API key, the SigV4 headers
66
+ it replaces with its own signature (`x-amz-date`, `x-amz-content-sha256`, and
67
+ `x-amz-security-token`), cookies, the hop-by-hop headers, and the `zp-` and
68
+ `cf-` headers added on the way in. It sets `content-type` itself.
69
+
70
+ `CountTokens` and `InvokeModelWithBidirectionalStream` aren't served. Calling
71
+ either returns a `400 ValidationException` naming the operations that are.
72
+
73
+ :::note
74
+
75
+ A Bedrock Runtime provider serves only these native paths. It doesn't serve the
76
+ [Universal API](./universal-api.mdx) endpoints (`/v1/chat/completions`,
77
+ `/v1/messages`, `/v1/responses`, `/v1/embeddings`), and its models don't appear
78
+ in an app's `GET /v1/models` listing. Add [Bedrock Mantle](./bedrock-mantle.mdx)
79
+ alongside it if you want both.
80
+
81
+ :::
82
+
83
+ ## Before you begin
84
+
85
+ You need:
86
+
87
+ - An AWS account with access to Amazon Bedrock in the region you plan to use.
88
+ - A **long-term IAM user access key pair**—an access key ID starting with `AKIA`
89
+ and its secret. Temporary STS credentials (`ASIA…`, or any pair with a session
90
+ token) are rejected: provider secrets are baked into the deployed gateway, so
91
+ a credential that expires in hours would break the gateway between redeploys.
92
+ - Two IAM permissions on the models you plan to call, in that region:
93
+ `bedrock:InvokeModel` and `bedrock:InvokeModelWithResponseStream`. That's the
94
+ whole list—`bedrock:Converse` and `bedrock:ConverseStream` aren't IAM actions,
95
+ and the Converse operations are authorized by the InvokeModel pair.
96
+ - An AI Gateway project in the Zuplo Portal, and an [app](./apps.mdx) to call
97
+ from. The app page shows its API URL, and its API key lives on the app's **API
98
+ Key** tab.
99
+
100
+ ## Add the provider
101
+
102
+ Adding or editing providers requires the **Edit** permission, granted to Zuplo
103
+ account and project **Admins**—see
104
+ [Managing Providers](./managing-providers.mdx).
105
+
106
+ <Stepper>
107
+
108
+ 1. Open
109
+ [**Settings → AI Providers**](https://portal.zuplo.com/+/account/project/ai/settings/data-models)
110
+ in your AI Gateway project in the Zuplo Portal.
111
+
112
+ 1. Click the **Add Provider** button.
113
+
114
+ 1. In the **AI Provider** list, select **Bedrock Runtime**.
115
+
116
+ 1. Review the **Provider Name**, which fills in as `bedrockruntime`. You can
117
+ replace it with your own name, but only now—the name is permanent after
118
+ creation, and it's the prefix in every model reference.
119
+
120
+ 1. In **AWS Region**, enter the lowercase code of the region you use Bedrock in,
121
+ such as `us-east-1`. The gateway sends this provider's requests to
122
+ `https://bedrock-runtime.<region>.amazonaws.com`—the standard endpoint
123
+ family, not the FIPS or dual-stack ones. Regions in the China partition
124
+ (`cn-`) aren't supported.
125
+
126
+ 1. In **Access Key ID**, enter the key ID, which starts with `AKIA`. In **Secret
127
+ Access Key**, enter the secret. AWS shows the secret only once, when the key
128
+ is created.
129
+
130
+ 1. Select the models to enable, then click **Create**.
131
+
132
+ </Stepper>
133
+
134
+ :::note
135
+
136
+ Saving provider settings triggers an automatic production deployment of your
137
+ gateway, because provider credentials are part of the deployed gateway. The
138
+ change is live once the deployment completes.
139
+
140
+ :::
141
+
142
+ ## Point your AWS SDK at the gateway
143
+
144
+ Two configuration changes, and **both are required**:
145
+
146
+ 1. Set `endpoint` to your app's API URL.
147
+ 2. Make the client send the app's API key as a bearer token.
148
+
149
+ The second one matters more than it looks. An existing client usually has AWS
150
+ credentials available—in the environment, in a shared profile, or from an
151
+ instance role—and the SDK signs with SigV4 whenever it finds any. It would then
152
+ never send your gateway key, and the request would fail with a `401`. Setting
153
+ the auth scheme explicitly is what prevents that.
154
+
155
+ ```ts
156
+ import {
157
+ BedrockRuntimeClient,
158
+ ConverseCommand,
159
+ } from "@aws-sdk/client-bedrock-runtime";
160
+
161
+ const apiKey = process.env.ZUPLO_APP_API_KEY;
162
+ if (!apiKey) {
163
+ throw new Error("Set ZUPLO_APP_API_KEY to your app's API key.");
164
+ }
165
+
166
+ const client = new BedrockRuntimeClient({
167
+ region: "us-east-1",
168
+ // Your app's API URL—no /v1, no trailing path.
169
+ endpoint:
170
+ "https://my-gateway-main-2e18f50.zuplo.app/config_fe0a04972d2848e0a94ae4b8bcd1497e",
171
+ // Send the app's API key as a bearer token instead of signing with SigV4.
172
+ authSchemePreference: ["httpBearerAuth"],
173
+ // `token` requires a string, so the check above is what makes this compile.
174
+ token: { token: apiKey },
175
+ });
176
+
177
+ // Unchanged from here down.
178
+ const response = await client.send(
179
+ new ConverseCommand({
180
+ modelId: "bedrockruntime/us.anthropic.claude-haiku-4-5-20251001-v1:0",
181
+ messages: [{ role: "user", content: [{ text: "Say hi" }] }],
182
+ }),
183
+ );
184
+ ```
185
+
186
+ Any AWS SDK that supports bearer-token authentication for Bedrock works the same
187
+ way—set the endpoint, supply the token, and make sure the client prefers bearer
188
+ auth over SigV4. Bearer-token support arrived in AWS SDK for JavaScript 3.840,
189
+ boto3 1.39, AWS SDK for Go 1.35, and AWS SDK for Java 2.31.74; use those
190
+ versions or later.
191
+
192
+ The gateway is the credential boundary: your client never holds AWS credentials,
193
+ and the gateway signs the upstream request with the IAM key pair you configured.
194
+
195
+ ## Model references
196
+
197
+ Apps reference models as `providerName/modelId`, where `providerName` is the
198
+ name you gave the provider configuration:
199
+
200
+ ```
201
+ bedrockruntime/us.anthropic.claude-haiku-4-5-20251001-v1:0
202
+ ```
203
+
204
+ The gateway strips its own prefix and sends AWS the model ID exactly as you
205
+ wrote it, so **anything Bedrock accepts works**—published model IDs,
206
+ cross-region inference profiles, and provisioned-throughput ARNs alike.
207
+
208
+ :::tip{title="Many models need an inference profile ID"}
209
+
210
+ Bedrock refuses a bare model ID for models it serves only through cross-region
211
+ inference:
212
+
213
+ ```
214
+ ValidationException: Invocation of model ID
215
+ anthropic.claude-haiku-4-5-20251001-v1:0 with on-demand throughput isn't
216
+ supported. Retry your request with the ID or ARN of an inference profile that
217
+ contains this model.
218
+ ```
219
+
220
+ Use the inference profile ID—usually the model ID with a regional prefix such as
221
+ `us.`, `eu.`, or `apac.`. AWS lists them under
222
+ [Supported Regions and models for inference profiles](https://docs.aws.amazon.com/bedrock/latest/userguide/inference-profiles-support.html).
223
+
224
+ :::
225
+
226
+ ## Pricing and budgets
227
+
228
+ The gateway prices Bedrock Runtime requests from the model catalog by exact
229
+ model ID, the same as every other provider. Cross-region inference profiles are
230
+ priced too: the `us.`, `eu.`, `apac.`, `au.`, and `global.` IDs are catalog rows
231
+ in their own right. A model with no catalog row, such as a
232
+ provisioned-throughput ARN or an inference profile AWS added after the catalog,
233
+ is still served and still counts toward token and request
234
+ [budgets](./usage-limits.mdx), but is priced at zero. It doesn't count toward
235
+ spending budgets, and its response carries no `X-Cost-USD` header.
236
+
237
+ When a budget is exhausted, these routes answer
238
+ `400 ServiceQuotaExceededException`—not the `429` the Universal API returns. AWS
239
+ SDKs treat any `429` as throttling and retry it, and a spent budget doesn't
240
+ refill between retries, so the gateway uses the status Bedrock itself uses for
241
+ an exhausted quota. Your client sees the refusal immediately instead of retrying
242
+ into it.
243
+
244
+ ## Policies on Bedrock Runtime routes
245
+
246
+ These routes run your app's [policy chain](./policy-chains.mdx) like any other.
247
+ What changes is that the request body is Bedrock's shape rather than one the
248
+ gateway parses, so a policy that reads the body applies its `onUnknownShape`
249
+ setting instead. Each policy's default follows from its job: a guardrail fails
250
+ closed, while an observer or an optimization fails open.
251
+
252
+ | Policy | On Bedrock Runtime routes |
253
+ | ----------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------ |
254
+ | [Authentication](../policies/ai-gateway-auth-v2-inbound.mdx) | Works. Reads the app key from `Authorization: Bearer` |
255
+ | [Model Filtering](../policies/ai-gateway-model-filtering-v2-inbound.mdx) | Works. Refuses a model outside the allow list before any AWS call |
256
+ | [Metering and budgets](../policies/ai-gateway-metering-v2-inbound.mdx) | Works. Meters tokens and cost on all four operations, streamed or not |
257
+ | [DLP](../policies/ai-gateway-dlp-inbound.mdx) and content guardrails | **Blocks by default.** The gateway can't read these bodies, so the policy denies the request. Set `onUnknownShape` to `skip` to forward it uninspected |
258
+ | [Galileo](../policies/galileo-tracing-v2-inbound.mdx) and [Comet Opik](../policies/comet-opik-tracing-v2-inbound.mdx) tracing | **Skipped by default.** The request goes through untraced. Set `onUnknownShape` to `deny` to make a trace a hard requirement |
259
+ | Semantic Cache | Skipped |
260
+
261
+ The table lists every policy the gateway supports on these routes. It audits the
262
+ chain and refuses any other policy, such as a custom policy, Smart Router, or
263
+ [Fallback Model](./fallback.mdx), with a `400 ValidationException` that names
264
+ the policy. Remove it from the chain to use Bedrock Runtime through that app.
265
+
266
+ If you need content inspection on Bedrock traffic, use
267
+ [Bedrock's own guardrails](https://docs.aws.amazon.com/bedrock/latest/userguide/guardrails.html)
268
+ through `guardrailConfig` in the request body—the gateway forwards it untouched.
269
+
270
+ Errors the gateway raises on these routes carry an `x-amzn-ErrorType` header, so
271
+ your SDK surfaces them as typed exceptions rather than as deserialization
272
+ failures.
273
+
274
+ ## Troubleshooting
275
+
276
+ **Every request returns `401`.** The client is signing with SigV4 instead of
277
+ sending the app's API key. Set `authSchemePreference` (or your SDK's equivalent)
278
+ to prefer bearer authentication, and confirm the token is the app's API key from
279
+ the app's **API Key** tab.
280
+
281
+ **`ValidationException` about on-demand throughput.** The model needs a
282
+ cross-region inference profile ID rather than the bare model ID—see
283
+ [Model references](#model-references).
284
+
285
+ **`403` from AWS that reads like a bad key.** Check that the IAM user has
286
+ `bedrock:InvokeModel` and `bedrock:InvokeModelWithResponseStream` on that model
287
+ _in the provider's region_, and that the model is enabled for your AWS account.
288
+
289
+ **The provider dialog rejects your key pair.** An access key ID starting with
290
+ `ASIA` is a temporary credential and is refused on purpose—it would expire while
291
+ baked into the deployed gateway. The dialog also rejects an access key ID that
292
+ isn't 16 to 128 uppercase letters and digits, a secret containing spaces or line
293
+ breaks, and either field filled in without the other.
294
+
295
+ **A `400` naming the supported operations.** You called `CountTokens` or
296
+ `InvokeModelWithBidirectionalStream`, which the gateway doesn't serve.
297
+
298
+ **`ServiceQuotaExceededException` you can't find in AWS.** It's a Zuplo budget,
299
+ not an AWS service quota. An exhausted [budget](./usage-limits.mdx) refuses
300
+ these routes with that exception—check the app's usage limits before you open a
301
+ quota ticket with AWS.
302
+
303
+ **Your app's model list is empty of Bedrock models.** Expected—Bedrock Runtime
304
+ models don't appear in `GET /v1/models`, because model IDs here are open-ended
305
+ (inference profiles and ARNs are valid and aren't catalog entries).
306
+
307
+ ## Next steps
308
+
309
+ - [AI Providers](./providers.mdx)—the capability matrix across every supported
310
+ provider.
311
+ - [Using Bedrock Mantle](./bedrock-mantle.mdx)—the other Amazon Bedrock
312
+ provider, for OpenAI- and Anthropic-shaped clients.
313
+ - [Managing Providers](./managing-providers.mdx)—edit models, keys, and the
314
+ region, and understand when changes deploy.
315
+ - [AI Gateway Apps](./apps.mdx)—create the apps that call your models.
316
+ - [Model Filtering policy](../policies/ai-gateway-model-filtering-v2-inbound.mdx)—control
317
+ which models each app can call.
@@ -23,6 +23,8 @@ Zuplo currently supports the following AI providers:
23
23
  serving Claude and every Foundry model family from your own Azure subscription
24
24
  - [Bedrock Mantle](./bedrock-mantle.mdx)—Amazon Bedrock's compatible-APIs
25
25
  endpoint, serving Claude models and models from many other vendors
26
+ - [Bedrock Runtime](./bedrock-runtime.mdx)—Amazon Bedrock's native API, for code
27
+ that already calls Bedrock with an AWS SDK
26
28
  - [Vertex AI](./vertex-ai.mdx)—Google Cloud's managed model platform, serving
27
29
  Gemini and Model Garden models on your own Google Cloud project
28
30
  - [Zuplo Demo](#zuplo-demo)—a free, keyless provider for trying the gateway
@@ -40,6 +42,7 @@ The following capabilities are supported across providers:
40
42
  | xAI | ✅ | ✅ | ❌ | ❌ |
41
43
  | Azure AI | ✅ | ✅ | ✅ | ✅ |
42
44
  | Bedrock Mantle | ✅ | ❌ | ✅ | ✅ |
45
+ | Bedrock Runtime | ❌ | ❌ | ❌ | ❌ |
43
46
  | Vertex AI | ✅ | ✅ | ❌ | ✅ |
44
47
  | Zuplo Demo | ✅ | ❌ | ❌ | ❌ |
45
48
  | OpenAI-compatible (Custom) | ✅ | ✅ | ❌ | ❌ |
@@ -54,6 +57,13 @@ Messages (plus chat completions through translation), while its other models
54
57
  serve chat completions and—per model—Responses. See
55
58
  [Using Bedrock Mantle](./bedrock-mantle.mdx#supported-endpoints-by-model-family).
56
59
 
60
+ Bedrock Runtime is the one provider with no Universal API capabilities, and the
61
+ table above says so. It serves Amazon Bedrock's **native** API instead, at its
62
+ own paths, so your existing AWS SDK code keeps working with the gateway in front
63
+ of it. See [Using Bedrock Runtime](./bedrock-runtime.mdx#supported-operations)
64
+ for the operations it serves, and add Bedrock Mantle alongside it if you also
65
+ want Bedrock models on the Universal API.
66
+
57
67
  Azure AI's capabilities split by model family, and within the OpenAI-compatible
58
68
  family they split per deployed model: a chat model serves chat completions and—
59
69
  per model and version—Responses, while an embedding model serves embeddings and
@@ -119,6 +129,26 @@ instead of an endpoint URL, and it accepts only long-term Bedrock API keys,
119
129
  which start with `ABSK`. For prerequisites, setup steps, code examples, and
120
130
  troubleshooting, see [Using Bedrock Mantle](./bedrock-mantle.mdx).
121
131
 
132
+ ## Bedrock Runtime
133
+
134
+ **Bedrock Runtime** is Amazon Bedrock's native API—the one the AWS SDKs call.
135
+ Unlike every other provider, it doesn't serve the
136
+ [Universal API](./universal-api.mdx): it serves Bedrock's own operations
137
+ (`Converse`, `ConverseStream`, `InvokeModel`, and
138
+ `InvokeModelWithResponseStream`) at Bedrock's own paths.
139
+
140
+ That makes it the provider to choose when you already have code calling Bedrock
141
+ with an AWS SDK. You point the client's endpoint at your app and give it the
142
+ app's API key; every call site stays as it is, and the gateway adds
143
+ authentication, model filtering, and usage metering in front of your own AWS
144
+ account.
145
+
146
+ It authenticates to AWS with a long-term IAM access key pair rather than a
147
+ Bedrock API key, so it needs its own provider configuration even if you also use
148
+ Bedrock Mantle on the same account. For prerequisites, setup steps, code
149
+ examples, and troubleshooting, see
150
+ [Using Bedrock Runtime](./bedrock-runtime.mdx).
151
+
122
152
  ## Vertex AI
123
153
 
124
154
  **Vertex AI** is Google Cloud's managed model platform. One provider
@@ -69,3 +69,33 @@ list—so clients that can't set a model still work.
69
69
  | `/v1/embeddings` | Embeddings for the providers marked in the [capability matrix](./providers.mdx#supported-providers) |
70
70
  | `/v1/responses` | OpenAI Responses API: OpenAI, and the OpenAI-compatible models that serve it on [Azure AI](./azure-ai.mdx) and [Bedrock Mantle](./bedrock-mantle.mdx) |
71
71
  | `/v1/messages` | Anthropic Messages API: Anthropic, and the Claude models of [Azure AI](./azure-ai.mdx), [Bedrock Mantle](./bedrock-mantle.mdx) and [Vertex AI](./vertex-ai.mdx) |
72
+
73
+ ## Request headers
74
+
75
+ The gateway forwards your request headers to the provider. A header your client
76
+ or your own policies set—a session ID, a trace header, a feature flag—arrives
77
+ with the request.
78
+
79
+ The gateway removes what it owns first:
80
+
81
+ | Removed | Why |
82
+ | ----------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------- |
83
+ | `authorization`, `x-api-key`, `api-key`, `proxy-authorization`, and cookies | Credentials addressed to the gateway. The provider gets its own credential from your provider configuration instead. |
84
+ | `content-type`, `accept`, `anthropic-version`, `anthropic-beta` | The gateway controls the wire format it sends upstream, which isn't always the one your client asked for. |
85
+ | `openai-organization`, `openai-project`, `x-goog-api-key`, `x-goog-user-project` | Another vendor's credentials and tenant selectors. They cause a `401` as soon as a request routes to a provider they don't belong to. |
86
+ | `host`, `connection`, `transfer-encoding`, `content-length`, and the rest of the hop-by-hop set | They describe the connection to the gateway, not the one to the provider. |
87
+ | `cdn-loop`, and anything starting with `zp-`, `cf-`, or `x-amz-` | They describe the path your request took to reach the gateway. |
88
+
89
+ Everything else reaches the provider, including `user-agent`, `x-forwarded-for`,
90
+ `true-client-ip`, `idempotency-key`, `x-request-id`, and the `x-stainless-*`
91
+ headers the OpenAI and Anthropic SDKs set.
92
+
93
+ To change what the provider receives, add a header policy—`set-headers-inbound`,
94
+ `remove-headers-inbound`, or `clear-headers-inbound`—to the app's
95
+ [policy chain](./policy-chains.mdx). Headers are copied after the chain runs, so
96
+ a policy that adds one puts it on the provider request too. Setting
97
+ `Authorization`, `x-api-key`, or `api-key` in a policy doesn't override the
98
+ credential from your provider configuration.
99
+
100
+ [Bedrock Runtime](./bedrock-runtime.mdx) isn't part of the Universal API and
101
+ forwards a different set, described on its own page.
@@ -228,6 +228,40 @@ the top of the hour. Every distinct `x-organization` value gets its own $50 per
228
228
  day, resetting at 00:00 UTC. The `app` rule caps the whole app at $2,500 per
229
229
  month, warning at $2,000, resetting on the first of the month.
230
230
 
231
+ ### Checking what a rule resolved to
232
+
233
+ A **By metadata** rule whose expression resolves to nothing budgets nothing, and
234
+ the request still succeeds. A rule that silently does nothing therefore looks
235
+ exactly like a rule that's working. Your gateway's request logs say which it is.
236
+
237
+ Every request that runs at least one **By metadata** rule logs
238
+ `AI Gateway budget dimensions resolved`, listing the rules that resolved and the
239
+ rules that didn't. Each rule that didn't carries a reason:
240
+
241
+ | Reason | What to change |
242
+ | --------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
243
+ | `no-such-property` | The expression is valid but found no value. The message names the property that broke the chain—check that the header or claim is really on the request. |
244
+ | `invalid-syntax` | The expression is outside the grammar. The message gives the position of the problem. |
245
+ | `per-request-identifier` | The value is unique to every request, so no two requests share a budget and no threshold is ever reached. Key on something that repeats, like a user or an organization. |
246
+ | `internal-field` | The value comes from a field the proxy populates, such as client certificate material. |
247
+ | `value-not-scalar` / `value-not-safe-integer` | The value isn't a string or a whole number. |
248
+ | `value-too-long` | The value is longer than 256 bytes. |
249
+ | `value-has-control-characters` | The value contains control characters. |
250
+
251
+ Resolved entries record the length of each value, not the value itself. A rule
252
+ whose expression names a credential—anything whose text contains `token`,
253
+ `secret`, `authorization`, `password`, `cookie`, `credential`, `bearer`, or
254
+ `api_key` in any spelling—never logs its value at all. Budgeting per API key is
255
+ a reasonable thing to do, and the key stays out of the log.
256
+
257
+ A rule that can never work, because its expression is unusable or the rule fails
258
+ validation, also logs a warning. Those warnings arrive once per configuration
259
+ rather than once per request, so a broken rule doesn't flood the log.
260
+
261
+ Verdicts name their rule too. A block or warning from a **By metadata** rule
262
+ carries the expression and its `ruleId`; one from an app-wide budget carries
263
+ neither. That's how you tell which rule refused a request.
264
+
231
265
  ## Setting team and gateway limits
232
266
 
233
267
  A team budget covers the combined usage of its apps and sub-teams. A gateway
@@ -41,7 +41,7 @@ Wrap Markdown lists with the `Stepper` component to create a vertical stepper li
41
41
  </div>
42
42
  <div className="flex-1">
43
43
 
44
- <Stepper>
44
+ <Stepper toc={false}>
45
45
 
46
46
  1. **Identify the Problem**
47
47
  1. **Plan Your Project**
@@ -52,6 +52,39 @@ Wrap Markdown lists with the `Stepper` component to create a vertical stepper li
52
52
  </div>
53
53
  </div>
54
54
 
55
+ ## Table of Contents
56
+
57
+ Steps are anchorable and show up in the "On this page" sidebar, nested one level below the heading
58
+ they follow:
59
+
60
+ | Stepper placed after… | Steps appear as… |
61
+ | ------------------------------------- | ----------------------------------------------- |
62
+ | The page title (or no heading at all) | Top-level entries |
63
+ | An `h2` | Sub-entries of that `h2` |
64
+ | An `h3` or deeper | Nothing — the same cut-off an `h4` heading hits |
65
+
66
+ That means a page that is nothing but a stepper (a tutorial, for example) gets a usable table of
67
+ contents automatically, while a stepper buried inside an existing section doesn't flood it.
68
+
69
+ Each step's title — the first line of the list item — becomes the entry. A step whose first block
70
+ isn't text (a code block, for instance) is skipped.
71
+
72
+ ### Opting out
73
+
74
+ Set `toc={false}` for a stepper that is a quick checklist rather than a section of the page worth
75
+ linking to:
76
+
77
+ <!-- prettier-ignore -->
78
+ ```tsx
79
+ <Stepper toc={false}>
80
+
81
+ 1. **Find the reason code**
82
+ 1. **Look up the code**
83
+ 1. **Re-file**
84
+
85
+ </Stepper>
86
+ ```
87
+
55
88
  ## Advanced Example
56
89
 
57
90
  <Stepper>
@@ -112,6 +112,10 @@ dist/
112
112
  └── ...
113
113
  ```
114
114
 
115
+ ::if{mode=opensource}
116
+
117
+ ::
118
+
115
119
  **Important:** Individual `.md` files are only kept in the final build if `publishMarkdown: true`.
116
120
  If only `llmsTxt` or `llmsTxtFull` is enabled, the `.md` files are generated temporarily during the
117
121
  build but deleted after the `llms.txt` files are created.
@@ -1,5 +1,3 @@
1
- # AI Gateway Authentication
2
-
3
1
  The AI Gateway Authentication policy authenticates requests with an AI Gateway
4
2
  application API key. After a key is accepted, the calling application is
5
3
  identified on `request.user` — `sub` is the application name and `data` its
@@ -114,6 +112,11 @@ curl https://gateway.example.com/v1/chat/completions \
114
112
  Authentication scheme matching is case-insensitive. A missing key, an invalid
115
113
  scheme, or a key that is not authorized receives a `401 Unauthorized` response.
116
114
 
115
+ Once the key is accepted, the policy removes the `authHeader` header from the
116
+ request. The application key never reaches an upstream provider or a policy
117
+ later in the chain, whatever header name it arrived in. Read the caller's
118
+ identity from `request.user` instead.
119
+
117
120
  ## Use a custom header
118
121
 
119
122
  Set `authHeader` to accept the key from another header. Set `authScheme` to an
@@ -1,5 +1,3 @@
1
- # AI Gateway Configuration Executor
2
-
3
1
  The AI Gateway Configuration Executor loads each application's configuration
4
2
  (when auth or `ai-gateway-configuration-loader-v2-inbound` has not already) and
5
3
  runs its ordered inbound policy chain. Configuration comes from route-level
@@ -408,6 +406,32 @@ The corresponding expression is `request.headers.get("x-budget-customer")`.
408
406
  Configuration code should create that ordinary string and pass the enclosing
409
407
  object to `JSON.stringify`; the serializer adds the JSON transport escaping.
410
408
 
409
+ Headers you set or remove in the inbound chain control what reaches your AI
410
+ provider. For example, you can add a session header or remove an internal
411
+ customer header before sending the request. Gateway-owned headers are excluded,
412
+ including credentials, `Content-Type`, `Accept`, and headers starting with `zp-`
413
+ or `cf-`; setting a credential header does not override your configured provider
414
+ credential.
415
+
416
+ That includes headers you add only for the gateway's own use. The
417
+ `x-budget-customer` header above carries the caller's user id, and unless you
418
+ remove it after the metering policy has read it, the provider receives it on
419
+ every request. Add a `remove-headers-inbound` entry after the metering entry:
420
+
421
+ ```json
422
+ [
423
+ { "name": "set-budget-dimension" },
424
+ { "name": "ai-gateway-metering-v2-inbound" },
425
+ {
426
+ "name": "remove-headers-inbound",
427
+ "options": { "headers": ["x-budget-customer"] }
428
+ }
429
+ ]
430
+ ```
431
+
432
+ Declare `remove-headers-inbound` in `config/policies.json` so the chain can
433
+ select it.
434
+
411
435
  Invalid budget rules and unsupported expressions are logged and skipped. Other
412
436
  valid rules continue to apply.
413
437
 
@@ -1,5 +1,3 @@
1
- # AI Gateway Configuration Loader
2
-
3
1
  The AI Gateway Configuration Loader loads each application's configuration into
4
2
  the request-scoped app-configuration channel. Configuration comes from
5
3
  route-level `ai-gateway-auth-v2-inbound` when that policy already ran, otherwise
@@ -43,16 +43,28 @@
43
43
  "pii": {
44
44
  "action": "mask"
45
45
  },
46
- "secret": {
47
- "action": "block"
46
+ "contact-email": {
47
+ "action": "off"
48
+ },
49
+ "finance-credit-card": {
50
+ "action": "mask"
51
+ },
52
+ "finance-iban": {
53
+ "action": "mask"
48
54
  }
49
55
  },
50
56
  "outbound": {
51
57
  "pii": {
52
- "action": "block"
58
+ "action": "mask"
53
59
  },
54
- "secret": {
55
- "action": "block"
60
+ "contact-email": {
61
+ "action": "off"
62
+ },
63
+ "finance-credit-card": {
64
+ "action": "mask"
65
+ },
66
+ "finance-iban": {
67
+ "action": "mask"
56
68
  }
57
69
  }
58
70
  }
@@ -6349,16 +6361,28 @@
6349
6361
  "pii": {
6350
6362
  "action": "mask"
6351
6363
  },
6352
- "secret": {
6353
- "action": "block"
6364
+ "contact-email": {
6365
+ "action": "off"
6366
+ },
6367
+ "finance-credit-card": {
6368
+ "action": "mask"
6369
+ },
6370
+ "finance-iban": {
6371
+ "action": "mask"
6354
6372
  }
6355
6373
  },
6356
6374
  "outbound": {
6357
6375
  "pii": {
6358
- "action": "block"
6376
+ "action": "mask"
6359
6377
  },
6360
- "secret": {
6361
- "action": "block"
6378
+ "contact-email": {
6379
+ "action": "off"
6380
+ },
6381
+ "finance-credit-card": {
6382
+ "action": "mask"
6383
+ },
6384
+ "finance-iban": {
6385
+ "action": "mask"
6362
6386
  }
6363
6387
  }
6364
6388
  }
@@ -1,5 +1,3 @@
1
- # AI Gateway Fallback Model
2
-
3
1
  Use this policy to add resilience to a model selection created by Model
4
2
  Filtering or a custom routing policy. Place it after Model Filtering:
5
3
 
@@ -1,5 +1,3 @@
1
- # AI Gateway Metering
2
-
3
1
  AI Gateway Metering records application usage and configures the app's own
4
2
  budgets before the provider request runs. It meters spend, tokens, and requests.
5
3
  Budget rules can cover the whole application or each distinct value of an
@@ -1,5 +1,3 @@
1
- # AI Gateway Model Filtering
2
-
3
1
  Use this policy when an AI Gateway route must restrict which models clients may
4
2
  select. Without it, an application can use any available model from the
5
3
  providers configured for the Zuplo project. The policy is optional.
@@ -1,5 +1,3 @@
1
- # AI Gateway Semantic Cache
2
-
3
1
  AI Gateway Semantic Cache answers a request from a previous response when the
4
2
  new prompt is semantically similar to one already seen. A hit skips the provider
5
3
  call. One inbound policy handles both directions: it checks the cache on the way
@@ -1,5 +1,3 @@
1
- # AI Gateway Smart Router
2
-
3
1
  Use this policy to classify the last user prompt on Chat Completions, Responses,
4
2
  and Anthropic Messages requests. Using the classification results, configure
5
3
  where to route the request based on its complexity.
@@ -268,3 +266,10 @@ Invalid options, classifier timeouts, empty classifier responses, and smart
268
266
  routing catalog errors are logged and the original request continues. Chat
269
267
  Completions, Responses, and Anthropic Messages are classified automatically.
270
268
  Embeddings and other non-AI paths are skipped.
269
+
270
+ One shape is refused rather than skipped. A Bedrock Runtime request
271
+ (`/model/{modelId}/{operation}`) carries a model-native body that the gateway
272
+ does not parse, so there is no prompt to classify, and letting it continue would
273
+ present your routing as in effect when it was not. The policy answers a
274
+ `400 ValidationException` in the AWS error envelope, naming the policy. Remove
275
+ the policy from that route to use Bedrock Runtime through it.
@@ -1,5 +1,3 @@
1
- # Akamai AI Firewall
2
-
3
1
  The Akamai AI Firewall policy sends prompts and completions to
4
2
  [Akamai Firewall for AI](https://www.akamai.com/products/firewall-for-ai) and
5
3
  blocks content that your Akamai configuration denies. One inbound policy covers
@@ -111,7 +111,7 @@ is working as expected.
111
111
 
112
112
  You have now set up Auth0 JWT Authentication on your API Gateway.
113
113
 
114
- ## OAuth 2.0 Protected Resource Metadata
114
+ ### OAuth 2.0 Protected Resource Metadata
115
115
 
116
116
  The Auth0 JWT Auth policy supports OAuth protected resource metadata discovery.
117
117
  To enable this feature, set the `oAuthResourceMetadataEnabled` option to `true`
@@ -1,5 +1,3 @@
1
- # Comet Opik Tracing
2
-
3
1
  The Comet Opik Tracing policy integrates
4
2
  [Comet Opik](https://www.comet.com/docs/opik/) with the AI Gateway. It captures
5
3
  LLM inputs, outputs, model information, token usage, request metadata, and
@@ -1,5 +1,3 @@
1
- # Galileo Tracing
2
-
3
1
  The Galileo Tracing policy integrates [Galileo](https://www.galileo.ai/) with
4
2
  the AI Gateway. It automatically records LLM inputs, outputs, model information,
5
3
  token usage, request metadata, and timing so you can debug applications and
@@ -1,5 +1,3 @@
1
- # MCP Auth0 OAuth Inbound
2
-
3
1
  Authenticate MCP gateway requests using a gateway-issued OAuth access token,
4
2
  with browser login delegated to Auth0.
5
3
 
@@ -52,7 +52,7 @@
52
52
  },
53
53
  "clientSecret": {
54
54
  "type": "string",
55
- "examples": ["$env(MCP_AUTH0_CLIENT_SECRET)"],
55
+ "examples": ["$env(AUTH0_CLIENT_SECRET)"],
56
56
  "description": "The Auth0 client\\_secret. Use $env(...) to source from a secret environment variable."
57
57
  },
58
58
  "scope": {
@@ -209,7 +209,7 @@
209
209
  "sessionTtlSeconds": 28800,
210
210
  "stateTtlSeconds": 900
211
211
  },
212
- "clientSecret": "$env(MCP_AUTH0_CLIENT_SECRET)",
212
+ "clientSecret": "$env(AUTH0_CLIENT_SECRET)",
213
213
  "gateway": {
214
214
  "accessTokenTtlSeconds": 900,
215
215
  "cimdEnabled": true,
@@ -1,5 +1,3 @@
1
- # MCP Clerk OAuth
2
-
3
1
  Authenticates MCP clients with gateway-issued OAuth tokens and delegates browser
4
2
  login to a Clerk OAuth application.
5
3
 
@@ -1,5 +1,3 @@
1
- # MCP Amazon Cognito OAuth Inbound
2
-
3
1
  Authenticate MCP gateway requests using a gateway-issued OAuth access token,
4
2
  with browser login delegated to Amazon Cognito.
5
3
 
@@ -1,5 +1,3 @@
1
- # MCP Microsoft Entra OAuth Inbound
2
-
3
1
  Authenticate MCP gateway requests using a gateway-issued OAuth access token,
4
2
  with browser login delegated to Microsoft Entra ID.
5
3
 
@@ -1,5 +1,3 @@
1
- # MCP Google OAuth Inbound
2
-
3
1
  Authenticate MCP gateway requests using a gateway-issued OAuth access token,
4
2
  with browser login delegated to Google.
5
3
 
@@ -1,5 +1,3 @@
1
- # MCP Keycloak OAuth
2
-
3
1
  The MCP Keycloak OAuth policy is a provider-specific wrapper around the generic
4
2
  MCP OAuth inbound policy. It keeps the gateway OAuth behavior the same, but lets
5
3
  you configure Keycloak with the values an administrator normally has:
@@ -1,5 +1,3 @@
1
- # MCP Logto OAuth Inbound
2
-
3
1
  Authenticate MCP gateway requests using a gateway-issued OAuth access token,
4
2
  with browser login delegated to Logto.
5
3
 
@@ -1,5 +1,3 @@
1
- # MCP OAuth Inbound
2
-
3
1
  Authenticate MCP gateway requests using a gateway-issued OAuth access token.
4
2
 
5
3
  ## How it works
@@ -73,7 +73,7 @@
73
73
  "type": "string",
74
74
  "format": "uri",
75
75
  "examples": ["https://my-tenant.us.auth0.com/authorize"],
76
- "description": "The IdP /authorize endpoint to redirect the user to. For local development on loopback, use http://127.0.0.1:9000/oauth/dev-login."
76
+ "description": "The IdP /authorize endpoint to redirect the user to. For local development on loopback, use http://127.0.0.1:9000/\\_\\_zuplo/oauth/dev-login (the gateway's default basePath is /\\_\\_zuplo; adjust if the plugin is configured with a different one)."
77
77
  },
78
78
  "tokenUrl": {
79
79
  "type": "string",
@@ -1,5 +1,3 @@
1
- # MCP Okta OAuth Inbound
2
-
3
1
  Authenticate MCP gateway requests using a gateway-issued OAuth access token,
4
2
  with browser login delegated to Okta.
5
3
 
@@ -1,5 +1,3 @@
1
- # MCP OneLogin OAuth Inbound
2
-
3
1
  Authenticate MCP gateway requests using a gateway-issued OAuth access token,
4
2
  with browser login delegated to OneLogin.
5
3
 
@@ -1,5 +1,3 @@
1
- # MCP Ping OAuth Inbound
2
-
3
1
  Authenticate MCP gateway requests using a gateway-issued OAuth access token,
4
2
  with browser login delegated to PingOne.
5
3
 
@@ -108,6 +108,52 @@ as Entra tenant admin consent. If connections start requiring frequent
108
108
  reauthorization after setting `prompt: false`, remove the option so the consent
109
109
  grant is requested again.
110
110
 
111
+ ## Authorization Server Issuer Mismatch
112
+
113
+ Some providers publish inconsistent OAuth metadata: the protected-resource
114
+ document advertises a path-scoped authorization server, but that server's own
115
+ metadata reports a different (usually root-origin) `issuer`. ServiceNow is one —
116
+ its protected-resource metadata names
117
+ `https://<instance>.service-now.com/sncapps/...` while the metadata served there
118
+ reports `https://<instance>.service-now.com`. Atlassian and Okta
119
+ org-versus-custom authorization servers publish the same shape.
120
+
121
+ RFC 8414 section 3.3 requires a client to reject a metadata document whose
122
+ `issuer` differs from the identifier the well-known URL was built from, so the
123
+ gateway hard-fails discovery against these providers. Set
124
+ `skipIssuerMetadataValidation` to `true` on that connection to proceed anyway:
125
+
126
+ ```json
127
+ {
128
+ "name": "mcp-token-exchange-servicenow",
129
+ "policyType": "mcp-token-exchange-inbound",
130
+ "handler": {
131
+ "module": "$import(@zuplo/runtime/mcp-gateway)",
132
+ "export": "McpTokenExchangeInboundPolicy",
133
+ "options": {
134
+ "displayName": "ServiceNow",
135
+ "authMode": "user-oauth",
136
+ "skipIssuerMetadataValidation": true
137
+ }
138
+ }
139
+ }
140
+ ```
141
+
142
+ **Warning**: this puts the connection out of spec. The issuer check is an
143
+ unqualified MUST in both RFC 8414 section 3.3 and the MCP authorization spec,
144
+ whose own example is the attack it prevents — a document served from
145
+ `https://attacker.example/.well-known/oauth-authorization-server` claiming
146
+ `"issuer": "https://honest.example"` must be rejected. The check binds the
147
+ metadata to the TLS-authenticated host it came from, and with it off the gateway
148
+ trusts the authorization, token and JWKS endpoints from a document that never
149
+ proved it speaks for that issuer.
150
+
151
+ Only enable it for a specific upstream known to publish a mismatched issuer, and
152
+ only when the metadata URL's host is itself trusted. Never enable it as a
153
+ default. It relaxes the discovery-time check only: the RFC 9207
154
+ authorization-response check and the callback-leg authorization-server binding
155
+ still apply.
156
+
111
157
  ## ID-JAG Token Exchange (Cross-App Access)
112
158
 
113
159
  Set `authMode` to `id-jag` when the upstream is protected by an Identity
@@ -128,8 +174,8 @@ Use this mode in enterprise deployments where the gateway and the upstream trust
128
174
  the same identity provider (for example, Okta Cross-App Access), so upstream
129
175
  access follows the caller's identity without a per-user upstream consent flow.
130
176
  The `user-oauth`/`shared-oauth` options — `scopes`, `scopeDelimiter`, `prompt`,
131
- and `clientRegistration` — do not apply; the `id-jag` mode is configured
132
- entirely through the `idJag` option.
177
+ `skipIssuerMetadataValidation`, and `clientRegistration` — do not apply; the
178
+ `id-jag` mode is configured entirely through the `idJag` option.
133
179
 
134
180
  ```json
135
181
  {
@@ -56,6 +56,9 @@
56
56
  {
57
57
  "required": ["prompt"]
58
58
  },
59
+ {
60
+ "required": ["skipIssuerMetadataValidation"]
61
+ },
59
62
  {
60
63
  "required": ["clientRegistration"]
61
64
  }
@@ -120,6 +123,11 @@
120
123
  }
121
124
  ]
122
125
  },
126
+ "skipIssuerMetadataValidation": {
127
+ "type": "boolean",
128
+ "x-advanced": true,
129
+ "description": "Skips the RFC 8414 section 3.3 issuer-echo check when discovering the upstream authorization server. That check requires the `issuer` in the authorization server's metadata to equal the `authorization_servers` entry the protected-resource metadata advertised. Some providers publish a path-scoped authorization server whose metadata reports the root origin instead — for example ServiceNow advertises `https://<instance>.service-now.com/sncapps/...` but its metadata reports `https://<instance>.service-now.com` — so discovery hard-fails without this option. Warning: enabling this puts the connection out of spec. The check is an unqualified MUST in both RFC 8414 section 3.3 and the MCP authorization spec, which require rejecting a metadata document whose `issuer` differs from the identifier the well-known URL was built from; the spec's own example is a document served from `https://attacker.example/.well-known/oauth-authorization-server` claiming `\"issuer\": \"https://honest.example\"`. The echo check binds the metadata to the TLS-authenticated host it came from, and with it off the gateway trusts the authorization, token and JWKS endpoints from a document that never proved it speaks for that issuer. Only enable it for a specific upstream known to publish a mismatched issuer, and only when the metadata URL's host is itself trusted. It relaxes the discovery-time check only — the RFC 9207 authorization-response check and the callback-leg authorization-server binding still apply."
130
+ },
123
131
  "clientRegistration": {
124
132
  "x-advanced": true,
125
133
  "description": "OAuth client registration mode. Defaults to `auto`, which uses Client ID Metadata Documents when the upstream advertises support and falls back to Dynamic Client Registration otherwise.",
@@ -1,5 +1,3 @@
1
- # MCP WorkOS OAuth Inbound
2
-
3
1
  Authenticate MCP gateway requests using a gateway-issued OAuth access token,
4
2
  with browser login delegated to WorkOS.
5
3
 
@@ -1,5 +1,3 @@
1
- # Monetization Metering Policy
2
-
3
1
  The Monetization policy validates subscriptions and records usage. Meter usage
4
2
  is sent in a final response hook after status-code filtering.
5
3
 
@@ -9,6 +7,16 @@ is sent in a final response hook after status-code filtering.
9
7
  - `meterOnStatusCodes`: status codes/ranges that trigger metering.
10
8
  - auth/cache settings: `authHeader`, `authScheme`, `cacheTtlSeconds`.
11
9
 
10
+ ## Error responses
11
+
12
+ - Missing, malformed, invalid, or expired API-key credentials return
13
+ `401 Unauthorized`. When `authScheme` is set, the response includes a
14
+ `WWW-Authenticate` challenge for that scheme. An empty `authScheme` is
15
+ raw-header mode: the entire header value is the key, and `WWW-Authenticate` is
16
+ omitted.
17
+ - A valid API key whose subscription, payment status, or entitlements deny
18
+ access returns `403 Forbidden`.
19
+
12
20
  ### Static meter configuration
13
21
 
14
22
  ```json
@@ -74,7 +74,7 @@ is working as expected.
74
74
 
75
75
  You have now setup PropelAuth JWT Authentication on your API Gateway.
76
76
 
77
- ## OAuth 2.0 Protected Resource Metadata
77
+ ### OAuth 2.0 Protected Resource Metadata
78
78
 
79
79
  The Propel JWT Auth policy supports OAuth protected resource metadata discovery.
80
80
  To enable this feature, set the `oAuthResourceMetadataEnabled` option to `true`
@@ -34,7 +34,7 @@ Apply this policy to outbound requests in your route configuration:
34
34
  }
35
35
  ```
36
36
 
37
- # Masked secrets
37
+ ## Masked secrets
38
38
 
39
39
  - Zuplo API keys (i.e. `zpka_xxx`)
40
40
  - GitHub Tokens and Personal Access Tokens (i.e. `ghp_xxx`)
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "zuplo",
3
- "version": "7.7.16",
3
+ "version": "7.8.0",
4
4
  "type": "module",
5
5
  "description": "The official Zuplo CLI for local development and platform management",
6
6
  "homepage": "https://zuplo.com/docs/cli/overview",
@@ -32,9 +32,9 @@
32
32
  "zuplo": "zuplo.js"
33
33
  },
34
34
  "dependencies": {
35
- "@zuplo/cli": "7.7.16",
36
- "@zuplo/core": "7.7.16",
37
- "@zuplo/runtime": "7.7.16",
38
- "@zuplo/test": "7.7.16"
35
+ "@zuplo/cli": "7.8.0",
36
+ "@zuplo/core": "7.8.0",
37
+ "@zuplo/runtime": "7.8.0",
38
+ "@zuplo/test": "7.8.0"
39
39
  }
40
40
  }