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.
- package/docs/analytics/access-and-entitlements.md +27 -34
- package/docs/analytics/overview.md +7 -6
- package/docs/analytics/reference/url-parameters.md +2 -10
- package/docs/analytics/shared-controls.md +3 -10
- package/docs/analytics/tabs/agents.md +3 -3
- package/docs/analytics/tabs/requests.md +2 -4
- package/docs/articles/accounts/audit-logs.mdx +4 -4
- package/docs/articles/audit-logging.mdx +65 -0
- package/docs/articles/audit-logs.mdx +222 -0
- package/docs/articles/connect-to-aws-alb-with-mtls.mdx +89 -13
- package/docs/articles/{custom-audit-log-policy.mdx → custom-audit-logs.mdx} +26 -22
- package/docs/articles/graphql-security.mdx +2 -1
- package/docs/articles/graphql.mdx +8 -0
- package/docs/articles/opentelemetry.mdx +7 -5
- package/docs/articles/securing-backend-mtls.mdx +92 -3
- package/docs/articles/troubleshooting-slow-responses.mdx +4 -3
- package/docs/articles/troubleshooting.md +3 -1
- package/docs/policies/_index.md +3 -0
- package/docs/policies/audit-log-inbound/doc.md +16 -11
- package/docs/policies/authzen-inbound/schema.json +1 -1
- package/docs/policies/axiomatics-authz-inbound/schema.json +1 -1
- package/docs/policies/clerk-jwt-auth-inbound/schema.json +3 -3
- package/docs/policies/mcp-auth0-oauth-inbound/schema.json +8 -5
- package/docs/policies/mcp-clerk-oauth-inbound/schema.json +78 -0
- package/docs/policies/mcp-cognito-oauth-inbound/schema.json +78 -0
- package/docs/policies/mcp-entra-oauth-inbound/schema.json +78 -0
- package/docs/policies/mcp-google-oauth-inbound/schema.json +78 -0
- package/docs/policies/mcp-keycloak-oauth-inbound/schema.json +78 -0
- package/docs/policies/mcp-logto-oauth-inbound/schema.json +78 -0
- package/docs/policies/mcp-oauth-inbound/schema.json +8 -5
- package/docs/policies/mcp-okta-oauth-inbound/schema.json +78 -0
- package/docs/policies/mcp-onelogin-oauth-inbound/schema.json +78 -0
- package/docs/policies/mcp-ping-oauth-inbound/schema.json +78 -0
- package/docs/policies/mcp-token-exchange-inbound/doc.md +72 -4
- package/docs/policies/mcp-token-exchange-inbound/intro.md +5 -4
- package/docs/policies/mcp-token-exchange-inbound/schema.json +277 -2
- package/docs/policies/mcp-workos-oauth-inbound/schema.json +78 -0
- package/docs/policies/mtls-auth-inbound/intro.md +52 -5
- package/docs/policies/okta-fga-authz-inbound/schema.json +1 -1
- package/docs/policies/open-id-jwt-auth-inbound/schema.json +3 -3
- package/docs/policies/openfga-authz-inbound/schema.json +1 -1
- package/docs/policies/propel-auth-jwt-inbound/schema.json +3 -3
- package/docs/policies/require-user-claims-inbound/doc.md +120 -0
- package/docs/policies/require-user-claims-inbound/intro.md +9 -0
- package/docs/policies/require-user-claims-inbound/schema.json +1323 -0
- package/docs/policies/semantic-cache-inbound/schema.json +1 -1
- package/docs/policies/upstream-aws-federated-auth-inbound/doc.md +78 -0
- package/docs/policies/upstream-aws-federated-auth-inbound/intro.md +20 -0
- package/docs/policies/upstream-aws-federated-auth-inbound/schema.json +98 -0
- package/docs/policies/upstream-aws-service-auth-inbound/doc.md +89 -0
- package/docs/policies/upstream-aws-service-auth-inbound/intro.md +19 -0
- package/docs/policies/upstream-aws-service-auth-inbound/schema.json +113 -0
- package/docs/policies/upstream-azure-ad-service-auth-inbound/schema.json +4 -4
- package/docs/policies/upstream-gcp-federated-auth-inbound/doc.md +2 -2
- package/docs/policies/upstream-gcp-federated-auth-inbound/schema.json +5 -5
- package/docs/policies/upstream-gcp-service-auth-inbound/doc.md +3 -3
- package/docs/policies/upstream-gcp-service-auth-inbound/schema.json +3 -3
- package/docs/policies/upstream-zuplo-jwt-auth-inbound/schema.json +19 -0
- package/docs/programmable-api/overview.mdx +0 -7
- package/package.json +4 -4
- package/docs/programmable-api/audit-log.mdx +0 -74
|
@@ -4,10 +4,11 @@ The `mcp-token-exchange-inbound` policy resolves gateway-managed upstream MCP
|
|
|
4
4
|
credentials and applies them to the request before the normal Zuplo route
|
|
5
5
|
handler forwards it.
|
|
6
6
|
|
|
7
|
-
Use this policy only when Zuplo manages upstream
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
7
|
+
Use this policy only when Zuplo manages upstream credentials: per-user OAuth
|
|
8
|
+
(`user-oauth`), a gateway-wide shared OAuth grant (`shared-oauth`), or ID-JAG
|
|
9
|
+
token exchange (`id-jag`). If the upstream is public, uses an API key header, or
|
|
10
|
+
only needs static routing/context headers, omit this policy and compose the
|
|
11
|
+
existing Zuplo header/auth policies instead.
|
|
11
12
|
|
|
12
13
|
Zuplo is only the gateway. It discovers the upstream MCP server, sends users
|
|
13
14
|
through the upstream OAuth flow, stores the resulting upstream connection, and
|
|
@@ -107,6 +108,73 @@ as Entra tenant admin consent. If connections start requiring frequent
|
|
|
107
108
|
reauthorization after setting `prompt: false`, remove the option so the consent
|
|
108
109
|
grant is requested again.
|
|
109
110
|
|
|
111
|
+
## ID-JAG Token Exchange (Cross-App Access)
|
|
112
|
+
|
|
113
|
+
Set `authMode` to `id-jag` when the upstream is protected by an Identity
|
|
114
|
+
Assertion JWT Authorization Grant (ID-JAG) Resource Authorization Server, the
|
|
115
|
+
pattern also known as Cross-App Access (XAA). Instead of sending users through
|
|
116
|
+
the upstream's browser OAuth flow, the gateway obtains the upstream credential
|
|
117
|
+
in two server-to-server steps:
|
|
118
|
+
|
|
119
|
+
1. **IdP token exchange**: the gateway exchanges the caller's identity assertion
|
|
120
|
+
at the configured identity provider's token endpoint for an ID-JAG, sending
|
|
121
|
+
the configured `audience` (the Resource Authorization Server) and `resource`
|
|
122
|
+
(the upstream MCP server).
|
|
123
|
+
2. **Resource AS redemption**: the gateway redeems the ID-JAG at the upstream
|
|
124
|
+
Resource Authorization Server's token endpoint using the `jwt-bearer` grant
|
|
125
|
+
and receives the upstream access token it attaches to the forwarded request.
|
|
126
|
+
|
|
127
|
+
Use this mode in enterprise deployments where the gateway and the upstream
|
|
128
|
+
trust the same identity provider (for example, Okta Cross-App Access), so
|
|
129
|
+
upstream access follows the caller's identity without a per-user upstream
|
|
130
|
+
consent flow. The `user-oauth`/`shared-oauth` options — `scopes`,
|
|
131
|
+
`scopeDelimiter`, `prompt`, and `clientRegistration` — do not apply; the
|
|
132
|
+
`id-jag` mode is configured entirely through the `idJag` option.
|
|
133
|
+
|
|
134
|
+
```json
|
|
135
|
+
{
|
|
136
|
+
"name": "mcp-token-exchange-acme",
|
|
137
|
+
"policyType": "mcp-token-exchange-inbound",
|
|
138
|
+
"handler": {
|
|
139
|
+
"module": "$import(@zuplo/runtime/mcp-gateway)",
|
|
140
|
+
"export": "McpTokenExchangeInboundPolicy",
|
|
141
|
+
"options": {
|
|
142
|
+
"displayName": "Acme",
|
|
143
|
+
"authMode": "id-jag",
|
|
144
|
+
"idJag": {
|
|
145
|
+
"scopes": ["mcp:tools"],
|
|
146
|
+
"idp": {
|
|
147
|
+
"tokenUrl": "https://idp.example.com/oauth2/token",
|
|
148
|
+
"clientAuth": {
|
|
149
|
+
"method": "client_secret_post",
|
|
150
|
+
"clientId": "gateway-client",
|
|
151
|
+
"clientSecret": "$env(IDP_CLIENT_SECRET)"
|
|
152
|
+
}
|
|
153
|
+
},
|
|
154
|
+
"resourceAs": {
|
|
155
|
+
"tokenUrl": "https://auth.acme-mcp.example.com/oauth2/token",
|
|
156
|
+
"audience": "https://auth.acme-mcp.example.com",
|
|
157
|
+
"resource": "https://mcp.acme.example.com/mcp",
|
|
158
|
+
"clientAuth": {
|
|
159
|
+
"method": "client_secret_post",
|
|
160
|
+
"clientId": "gateway-resource-client",
|
|
161
|
+
"clientSecret": "$env(RESOURCE_AS_CLIENT_SECRET)"
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
```
|
|
169
|
+
|
|
170
|
+
Both `clientAuth` blocks also accept `client_secret_basic` and
|
|
171
|
+
`private_key_jwt`. Use `private_key_jwt` for providers such as Okta that
|
|
172
|
+
require a signed client assertion for token exchange; it takes `privateKeyPem`,
|
|
173
|
+
an optional `keyId`, and an `algorithm` (default `RS256`). Source secrets and
|
|
174
|
+
private keys from environment variables with `$env(VAR_NAME)`. When `resource`
|
|
175
|
+
is omitted, the gateway defaults it to the upstream MCP server URL from the
|
|
176
|
+
route handler's `rewritePattern`.
|
|
177
|
+
|
|
110
178
|
## Route Shape
|
|
111
179
|
|
|
112
180
|
Publish both MCP transport methods as one Zuplo multi-method operation using
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
Resolve gateway-managed upstream MCP credentials and apply them to the request.
|
|
2
2
|
|
|
3
|
-
Use this after gateway auth when the upstream requires Zuplo-managed
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
3
|
+
Use this after gateway auth when the upstream requires Zuplo-managed
|
|
4
|
+
credentials: per-user OAuth, shared OAuth, or ID-JAG (Cross-App Access) token
|
|
5
|
+
exchange. Omit it for public upstreams or upstreams handled by ordinary Zuplo
|
|
6
|
+
header/API-key policies. The route should use `McpProxyHandler` with the
|
|
7
|
+
upstream URL configured on the handler.
|
|
@@ -34,6 +34,38 @@
|
|
|
34
34
|
"description": "The options for this policy.",
|
|
35
35
|
"additionalProperties": false,
|
|
36
36
|
"required": ["displayName", "authMode"],
|
|
37
|
+
"if": {
|
|
38
|
+
"properties": {
|
|
39
|
+
"authMode": {
|
|
40
|
+
"const": "id-jag"
|
|
41
|
+
}
|
|
42
|
+
},
|
|
43
|
+
"required": ["authMode"]
|
|
44
|
+
},
|
|
45
|
+
"then": {
|
|
46
|
+
"required": ["idJag"],
|
|
47
|
+
"not": {
|
|
48
|
+
"anyOf": [
|
|
49
|
+
{
|
|
50
|
+
"required": ["scopes"]
|
|
51
|
+
},
|
|
52
|
+
{
|
|
53
|
+
"required": ["scopeDelimiter"]
|
|
54
|
+
},
|
|
55
|
+
{
|
|
56
|
+
"required": ["prompt"]
|
|
57
|
+
},
|
|
58
|
+
{
|
|
59
|
+
"required": ["clientRegistration"]
|
|
60
|
+
}
|
|
61
|
+
]
|
|
62
|
+
}
|
|
63
|
+
},
|
|
64
|
+
"else": {
|
|
65
|
+
"not": {
|
|
66
|
+
"required": ["idJag"]
|
|
67
|
+
}
|
|
68
|
+
},
|
|
37
69
|
"properties": {
|
|
38
70
|
"id": {
|
|
39
71
|
"type": "string",
|
|
@@ -57,8 +89,8 @@
|
|
|
57
89
|
},
|
|
58
90
|
"authMode": {
|
|
59
91
|
"type": "string",
|
|
60
|
-
"enum": ["user-oauth", "shared-oauth"],
|
|
61
|
-
"description": "Authentication mode. `user-oauth` performs per-user OAuth federation; `shared-oauth` uses a gateway-wide OAuth grant."
|
|
92
|
+
"enum": ["user-oauth", "shared-oauth", "id-jag"],
|
|
93
|
+
"description": "Authentication mode. `user-oauth` performs per-user OAuth federation; `shared-oauth` uses a gateway-wide OAuth grant; `id-jag` exchanges the caller's identity assertion at the configured IdP for an ID-JAG (Identity Assertion JWT Authorization Grant, also known as Cross-App Access / XAA), then redeems it at the upstream Resource Authorization Server for an upstream access token."
|
|
62
94
|
},
|
|
63
95
|
"scopes": {
|
|
64
96
|
"type": "array",
|
|
@@ -126,6 +158,243 @@
|
|
|
126
158
|
}
|
|
127
159
|
}
|
|
128
160
|
]
|
|
161
|
+
},
|
|
162
|
+
"idJag": {
|
|
163
|
+
"type": "object",
|
|
164
|
+
"additionalProperties": false,
|
|
165
|
+
"required": ["idp", "resourceAs"],
|
|
166
|
+
"description": "ID-JAG (Cross-App Access / XAA) token-exchange configuration. Required when `authMode` is `id-jag`; not used by the OAuth modes.",
|
|
167
|
+
"properties": {
|
|
168
|
+
"scopes": {
|
|
169
|
+
"type": "array",
|
|
170
|
+
"default": [],
|
|
171
|
+
"description": "Scopes to request on the ID-JAG token exchange at the IdP.",
|
|
172
|
+
"items": {
|
|
173
|
+
"type": "string"
|
|
174
|
+
}
|
|
175
|
+
},
|
|
176
|
+
"scopeDelimiter": {
|
|
177
|
+
"type": "string",
|
|
178
|
+
"default": " ",
|
|
179
|
+
"description": "Delimiter used to join scopes in the token-exchange request. Defaults to a single space."
|
|
180
|
+
},
|
|
181
|
+
"idp": {
|
|
182
|
+
"type": "object",
|
|
183
|
+
"additionalProperties": false,
|
|
184
|
+
"required": ["tokenUrl", "clientAuth"],
|
|
185
|
+
"description": "The identity provider that exchanges the caller's identity assertion for an ID-JAG.",
|
|
186
|
+
"properties": {
|
|
187
|
+
"tokenUrl": {
|
|
188
|
+
"type": "string",
|
|
189
|
+
"format": "uri",
|
|
190
|
+
"description": "The IdP token endpoint used for the ID-JAG token exchange."
|
|
191
|
+
},
|
|
192
|
+
"clientAuth": {
|
|
193
|
+
"description": "Client authentication used at the token endpoint.",
|
|
194
|
+
"oneOf": [
|
|
195
|
+
{
|
|
196
|
+
"type": "object",
|
|
197
|
+
"additionalProperties": false,
|
|
198
|
+
"required": ["method", "clientId", "clientSecret"],
|
|
199
|
+
"properties": {
|
|
200
|
+
"method": {
|
|
201
|
+
"type": "string",
|
|
202
|
+
"const": "client_secret_post"
|
|
203
|
+
},
|
|
204
|
+
"clientId": {
|
|
205
|
+
"type": "string"
|
|
206
|
+
},
|
|
207
|
+
"clientSecret": {
|
|
208
|
+
"type": "string",
|
|
209
|
+
"examples": ["$env(IDP_CLIENT_SECRET)"],
|
|
210
|
+
"description": "OAuth client secret. Use `$env(VAR_NAME)` to source from an environment variable."
|
|
211
|
+
}
|
|
212
|
+
}
|
|
213
|
+
},
|
|
214
|
+
{
|
|
215
|
+
"type": "object",
|
|
216
|
+
"additionalProperties": false,
|
|
217
|
+
"required": ["method", "clientId", "clientSecret"],
|
|
218
|
+
"properties": {
|
|
219
|
+
"method": {
|
|
220
|
+
"type": "string",
|
|
221
|
+
"const": "client_secret_basic"
|
|
222
|
+
},
|
|
223
|
+
"clientId": {
|
|
224
|
+
"type": "string"
|
|
225
|
+
},
|
|
226
|
+
"clientSecret": {
|
|
227
|
+
"type": "string",
|
|
228
|
+
"examples": ["$env(IDP_CLIENT_SECRET)"],
|
|
229
|
+
"description": "OAuth client secret. Use `$env(VAR_NAME)` to source from an environment variable."
|
|
230
|
+
}
|
|
231
|
+
}
|
|
232
|
+
},
|
|
233
|
+
{
|
|
234
|
+
"type": "object",
|
|
235
|
+
"additionalProperties": false,
|
|
236
|
+
"required": ["method", "clientId", "privateKeyPem"],
|
|
237
|
+
"properties": {
|
|
238
|
+
"method": {
|
|
239
|
+
"type": "string",
|
|
240
|
+
"const": "private_key_jwt"
|
|
241
|
+
},
|
|
242
|
+
"clientId": {
|
|
243
|
+
"type": "string"
|
|
244
|
+
},
|
|
245
|
+
"privateKeyPem": {
|
|
246
|
+
"type": "string",
|
|
247
|
+
"examples": ["$env(IDP_PRIVATE_KEY_PEM)"],
|
|
248
|
+
"description": "PEM-encoded private key used to sign the client assertion. Use `$env(VAR_NAME)` to source from an environment variable."
|
|
249
|
+
},
|
|
250
|
+
"algorithm": {
|
|
251
|
+
"type": "string",
|
|
252
|
+
"enum": [
|
|
253
|
+
"RS256",
|
|
254
|
+
"RS384",
|
|
255
|
+
"RS512",
|
|
256
|
+
"ES256",
|
|
257
|
+
"ES384",
|
|
258
|
+
"ES512"
|
|
259
|
+
],
|
|
260
|
+
"default": "RS256",
|
|
261
|
+
"description": "JWS algorithm used to sign the client assertion."
|
|
262
|
+
},
|
|
263
|
+
"keyId": {
|
|
264
|
+
"type": "string",
|
|
265
|
+
"description": "Optional `kid` header set on the client assertion, for providers that select the verification key by key id."
|
|
266
|
+
},
|
|
267
|
+
"audience": {
|
|
268
|
+
"type": "string",
|
|
269
|
+
"format": "uri",
|
|
270
|
+
"description": "Optional override for the client assertion `aud` claim. Defaults to the token endpoint URL."
|
|
271
|
+
},
|
|
272
|
+
"expiresInSeconds": {
|
|
273
|
+
"type": "integer",
|
|
274
|
+
"default": 300,
|
|
275
|
+
"minimum": 1,
|
|
276
|
+
"maximum": 3600,
|
|
277
|
+
"description": "Client assertion lifetime in seconds."
|
|
278
|
+
}
|
|
279
|
+
}
|
|
280
|
+
}
|
|
281
|
+
]
|
|
282
|
+
}
|
|
283
|
+
}
|
|
284
|
+
},
|
|
285
|
+
"resourceAs": {
|
|
286
|
+
"type": "object",
|
|
287
|
+
"additionalProperties": false,
|
|
288
|
+
"required": ["tokenUrl", "audience", "clientAuth"],
|
|
289
|
+
"description": "The upstream Resource Authorization Server that redeems the ID-JAG for an upstream access token.",
|
|
290
|
+
"properties": {
|
|
291
|
+
"tokenUrl": {
|
|
292
|
+
"type": "string",
|
|
293
|
+
"format": "uri",
|
|
294
|
+
"description": "The Resource Authorization Server token endpoint where the gateway redeems the ID-JAG via the jwt-bearer grant."
|
|
295
|
+
},
|
|
296
|
+
"audience": {
|
|
297
|
+
"type": "string",
|
|
298
|
+
"description": "The `audience` value sent on the ID-JAG token exchange, identifying the Resource Authorization Server (typically its issuer)."
|
|
299
|
+
},
|
|
300
|
+
"resource": {
|
|
301
|
+
"type": "string",
|
|
302
|
+
"description": "Optional `resource` indicator sent on the token exchange, identifying the upstream MCP resource. Defaults to the upstream MCP server URL from the route handler's rewritePattern."
|
|
303
|
+
},
|
|
304
|
+
"clientAuth": {
|
|
305
|
+
"description": "Client authentication used at the token endpoint.",
|
|
306
|
+
"oneOf": [
|
|
307
|
+
{
|
|
308
|
+
"type": "object",
|
|
309
|
+
"additionalProperties": false,
|
|
310
|
+
"required": ["method", "clientId", "clientSecret"],
|
|
311
|
+
"properties": {
|
|
312
|
+
"method": {
|
|
313
|
+
"type": "string",
|
|
314
|
+
"const": "client_secret_post"
|
|
315
|
+
},
|
|
316
|
+
"clientId": {
|
|
317
|
+
"type": "string"
|
|
318
|
+
},
|
|
319
|
+
"clientSecret": {
|
|
320
|
+
"type": "string",
|
|
321
|
+
"examples": ["$env(IDP_CLIENT_SECRET)"],
|
|
322
|
+
"description": "OAuth client secret. Use `$env(VAR_NAME)` to source from an environment variable."
|
|
323
|
+
}
|
|
324
|
+
}
|
|
325
|
+
},
|
|
326
|
+
{
|
|
327
|
+
"type": "object",
|
|
328
|
+
"additionalProperties": false,
|
|
329
|
+
"required": ["method", "clientId", "clientSecret"],
|
|
330
|
+
"properties": {
|
|
331
|
+
"method": {
|
|
332
|
+
"type": "string",
|
|
333
|
+
"const": "client_secret_basic"
|
|
334
|
+
},
|
|
335
|
+
"clientId": {
|
|
336
|
+
"type": "string"
|
|
337
|
+
},
|
|
338
|
+
"clientSecret": {
|
|
339
|
+
"type": "string",
|
|
340
|
+
"examples": ["$env(IDP_CLIENT_SECRET)"],
|
|
341
|
+
"description": "OAuth client secret. Use `$env(VAR_NAME)` to source from an environment variable."
|
|
342
|
+
}
|
|
343
|
+
}
|
|
344
|
+
},
|
|
345
|
+
{
|
|
346
|
+
"type": "object",
|
|
347
|
+
"additionalProperties": false,
|
|
348
|
+
"required": ["method", "clientId", "privateKeyPem"],
|
|
349
|
+
"properties": {
|
|
350
|
+
"method": {
|
|
351
|
+
"type": "string",
|
|
352
|
+
"const": "private_key_jwt"
|
|
353
|
+
},
|
|
354
|
+
"clientId": {
|
|
355
|
+
"type": "string"
|
|
356
|
+
},
|
|
357
|
+
"privateKeyPem": {
|
|
358
|
+
"type": "string",
|
|
359
|
+
"examples": ["$env(IDP_PRIVATE_KEY_PEM)"],
|
|
360
|
+
"description": "PEM-encoded private key used to sign the client assertion. Use `$env(VAR_NAME)` to source from an environment variable."
|
|
361
|
+
},
|
|
362
|
+
"algorithm": {
|
|
363
|
+
"type": "string",
|
|
364
|
+
"enum": [
|
|
365
|
+
"RS256",
|
|
366
|
+
"RS384",
|
|
367
|
+
"RS512",
|
|
368
|
+
"ES256",
|
|
369
|
+
"ES384",
|
|
370
|
+
"ES512"
|
|
371
|
+
],
|
|
372
|
+
"default": "RS256",
|
|
373
|
+
"description": "JWS algorithm used to sign the client assertion."
|
|
374
|
+
},
|
|
375
|
+
"keyId": {
|
|
376
|
+
"type": "string",
|
|
377
|
+
"description": "Optional `kid` header set on the client assertion, for providers that select the verification key by key id."
|
|
378
|
+
},
|
|
379
|
+
"audience": {
|
|
380
|
+
"type": "string",
|
|
381
|
+
"format": "uri",
|
|
382
|
+
"description": "Optional override for the client assertion `aud` claim. Defaults to the token endpoint URL."
|
|
383
|
+
},
|
|
384
|
+
"expiresInSeconds": {
|
|
385
|
+
"type": "integer",
|
|
386
|
+
"default": 300,
|
|
387
|
+
"minimum": 1,
|
|
388
|
+
"maximum": 3600,
|
|
389
|
+
"description": "Client assertion lifetime in seconds."
|
|
390
|
+
}
|
|
391
|
+
}
|
|
392
|
+
}
|
|
393
|
+
]
|
|
394
|
+
}
|
|
395
|
+
}
|
|
396
|
+
}
|
|
397
|
+
}
|
|
129
398
|
}
|
|
130
399
|
}
|
|
131
400
|
}
|
|
@@ -137,6 +406,12 @@
|
|
|
137
406
|
"options": {
|
|
138
407
|
"displayName": "Linear",
|
|
139
408
|
"id": "linear",
|
|
409
|
+
"idJag": {
|
|
410
|
+
"idp": {},
|
|
411
|
+
"resourceAs": {},
|
|
412
|
+
"scopeDelimiter": " ",
|
|
413
|
+
"scopes": []
|
|
414
|
+
},
|
|
140
415
|
"scopes": [],
|
|
141
416
|
"summary": "Native Linear remote MCP server."
|
|
142
417
|
}
|
|
@@ -74,6 +74,84 @@
|
|
|
74
74
|
}
|
|
75
75
|
}
|
|
76
76
|
},
|
|
77
|
+
"idJag": {
|
|
78
|
+
"description": "Optional Identity Assertion JWT Authorization Grant (ID-JAG / XAA) support for the gateway token endpoint.",
|
|
79
|
+
"oneOf": [
|
|
80
|
+
{
|
|
81
|
+
"type": "object",
|
|
82
|
+
"additionalProperties": false,
|
|
83
|
+
"required": ["enabled"],
|
|
84
|
+
"properties": {
|
|
85
|
+
"enabled": {
|
|
86
|
+
"const": false,
|
|
87
|
+
"description": "Disable ID-JAG support."
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
},
|
|
91
|
+
{
|
|
92
|
+
"type": "object",
|
|
93
|
+
"additionalProperties": false,
|
|
94
|
+
"required": ["enabled"],
|
|
95
|
+
"properties": {
|
|
96
|
+
"enabled": {
|
|
97
|
+
"const": true,
|
|
98
|
+
"description": "Enable ID-JAG support."
|
|
99
|
+
},
|
|
100
|
+
"trustedIssuers": {
|
|
101
|
+
"type": "array",
|
|
102
|
+
"minItems": 1,
|
|
103
|
+
"description": "Trusted ID-JAG issuers. These values are never published in OAuth metadata. Omit to trust this policy's browser-login IdP.",
|
|
104
|
+
"items": {
|
|
105
|
+
"type": "object",
|
|
106
|
+
"additionalProperties": false,
|
|
107
|
+
"dependentRequired": {
|
|
108
|
+
"issuer": ["jwksUrl"],
|
|
109
|
+
"jwksUrl": ["issuer"]
|
|
110
|
+
},
|
|
111
|
+
"properties": {
|
|
112
|
+
"issuer": {
|
|
113
|
+
"type": "string",
|
|
114
|
+
"format": "uri",
|
|
115
|
+
"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."
|
|
116
|
+
},
|
|
117
|
+
"jwksUrl": {
|
|
118
|
+
"type": "string",
|
|
119
|
+
"format": "uri",
|
|
120
|
+
"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."
|
|
121
|
+
},
|
|
122
|
+
"expectedClientIds": {
|
|
123
|
+
"type": "array",
|
|
124
|
+
"items": {
|
|
125
|
+
"type": "string",
|
|
126
|
+
"minLength": 1
|
|
127
|
+
},
|
|
128
|
+
"description": "Optional allow-list of client IDs accepted from this issuer. The ID-JAG client_id must still match the authenticated token-endpoint client."
|
|
129
|
+
},
|
|
130
|
+
"subjectMapping": {
|
|
131
|
+
"type": "string",
|
|
132
|
+
"enum": [
|
|
133
|
+
"iss_prefix",
|
|
134
|
+
"iss_tenant_prefix",
|
|
135
|
+
"sub_id_only"
|
|
136
|
+
],
|
|
137
|
+
"default": "iss_prefix",
|
|
138
|
+
"description": "How the ID-JAG subject is mapped into the gateway subject ID."
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
},
|
|
143
|
+
"authorizationDetailsTypesAllowed": {
|
|
144
|
+
"type": "array",
|
|
145
|
+
"items": {
|
|
146
|
+
"type": "string",
|
|
147
|
+
"minLength": 1
|
|
148
|
+
},
|
|
149
|
+
"description": "Optional allow-list of RFC 9396 authorization_details type values accepted from ID-JAGs."
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
]
|
|
154
|
+
},
|
|
77
155
|
"browserLoginOverrides": {
|
|
78
156
|
"type": "object",
|
|
79
157
|
"description": "Optional overrides for the derived browser-login settings.",
|
|
@@ -1,7 +1,44 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
1
|
+
The `mtls-auth-inbound` policy is the enforcement step of client mutual TLS
|
|
2
|
+
(mTLS). It reads the verification result that Zuplo's edge proxy attaches to
|
|
3
|
+
each request and, when enforcement is enabled, rejects requests that don't
|
|
4
|
+
present a valid client certificate signed by a CA you trust. It is one part of a
|
|
5
|
+
complete client mTLS setup: you first upload the signing CA to your account,
|
|
6
|
+
then add this policy to the routes you want to protect.
|
|
7
|
+
|
|
8
|
+
For the full walkthrough — CA upload, configuration, testing with `curl`,
|
|
9
|
+
rotation, and troubleshooting (including the common
|
|
10
|
+
`FAILED to get issuer certificate` error) — see the
|
|
11
|
+
[Client mTLS authentication guide](https://zuplo.com/docs/articles/securing-the-gateway-with-client-mtls).
|
|
12
|
+
|
|
13
|
+
## Setting up client mTLS
|
|
14
|
+
|
|
15
|
+
This policy only enforces a result; it does not, on its own, make Zuplo verify
|
|
16
|
+
client certificates. The end-to-end setup is:
|
|
17
|
+
|
|
18
|
+
1. **Upload your CA certificate** to your account with the
|
|
19
|
+
[Zuplo CLI](https://zuplo.com/docs/cli/ca-certificate-create):
|
|
20
|
+
`zuplo ca-certificate create --name my_ca --cert ./ca.pem --account your-account`.
|
|
21
|
+
Upload the self-signed **root** CA that anchors the chain, not an
|
|
22
|
+
intermediate. CA certificates are scoped to your **account**, so once
|
|
23
|
+
uploaded, every gateway domain on the account verifies presented client
|
|
24
|
+
certificates against it.
|
|
25
|
+
2. **Add this policy** (`mtls-auth-inbound`) to each route that should require a
|
|
26
|
+
verified client certificate, and set `certIssuerDN` to pin the issuer (see
|
|
27
|
+
the options described below).
|
|
28
|
+
3. **Read the certificate** in your request handler or downstream policies from
|
|
29
|
+
`request.user.data.mtlsAuth`.
|
|
30
|
+
4. **Test** with a client certificate issued by (or chained to) your CA:
|
|
31
|
+
`curl --cert ./client.pem --key ./client.key https://your-gateway.zuplo.app/v1/example`.
|
|
32
|
+
|
|
33
|
+
See the
|
|
34
|
+
[full guide](https://zuplo.com/docs/articles/securing-the-gateway-with-client-mtls)
|
|
35
|
+
for CA management, custom domains, rotation, and troubleshooting.
|
|
36
|
+
|
|
37
|
+
## How the policy behaves
|
|
38
|
+
|
|
39
|
+
When enforcement is enabled, the policy rejects requests where no client
|
|
40
|
+
certificate was presented, certificate verification failed, or the certificate
|
|
41
|
+
metadata cannot be parsed.
|
|
5
42
|
|
|
6
43
|
When verification passes, the policy parses the client certificate metadata and
|
|
7
44
|
sets it on `request.user.data.mtlsAuth`. The metadata includes `subject`,
|
|
@@ -30,5 +67,15 @@ inspect `request.user.data.mtlsAuth.issuer` from a request signed by the desired
|
|
|
30
67
|
CA.
|
|
31
68
|
|
|
32
69
|
Note: this policy does not work with local development since it relies on
|
|
33
|
-
metadata from the upstream reverse proxy
|
|
70
|
+
metadata from the upstream reverse proxy. It is recommended to test this using a
|
|
34
71
|
working-copy or preview environment.
|
|
72
|
+
|
|
73
|
+
## Learn more
|
|
74
|
+
|
|
75
|
+
- [Client mTLS authentication guide](https://zuplo.com/docs/articles/securing-the-gateway-with-client-mtls)
|
|
76
|
+
— full end-to-end setup, CA management, and troubleshooting
|
|
77
|
+
- [`ca-certificate` CLI reference](https://zuplo.com/docs/cli/ca-certificate-create)
|
|
78
|
+
— upload, list, describe, rename, and delete account CA certificates
|
|
79
|
+
- [Gateway to Origin mTLS](https://zuplo.com/docs/articles/securing-backend-mtls)
|
|
80
|
+
— the reverse direction, where Zuplo authenticates to your backend with a
|
|
81
|
+
client certificate
|
|
@@ -54,7 +54,7 @@
|
|
|
54
54
|
"jwkUrl": {
|
|
55
55
|
"type": "string",
|
|
56
56
|
"examples": [
|
|
57
|
-
"https://
|
|
57
|
+
"https://my-tenant.us.auth0.com/.well-known/jwks.json"
|
|
58
58
|
],
|
|
59
59
|
"description": "the url of the JSON Web Key Set (JWKS) - this is used to validate the JWT token signature (either this or `secret` must be set)."
|
|
60
60
|
},
|
|
@@ -90,7 +90,7 @@
|
|
|
90
90
|
{
|
|
91
91
|
"issuer": "$env(AUTH_ISSUER)",
|
|
92
92
|
"audience": "$env(AUTH_AUDIENCE)",
|
|
93
|
-
"jwkUrl": "https://
|
|
93
|
+
"jwkUrl": "https://my-tenant.us.auth0.com/.well-known/jwks.json"
|
|
94
94
|
},
|
|
95
95
|
{
|
|
96
96
|
"issuer": "$env(AUTH_ISSUER)",
|
|
@@ -107,7 +107,7 @@
|
|
|
107
107
|
"options": {
|
|
108
108
|
"issuer": "$env(AUTH_ISSUER)",
|
|
109
109
|
"audience": "$env(AUTH_AUDIENCE)",
|
|
110
|
-
"jwkUrl": "https://
|
|
110
|
+
"jwkUrl": "https://my-tenant.us.auth0.com/.well-known/jwks.json"
|
|
111
111
|
}
|
|
112
112
|
},
|
|
113
113
|
{
|
|
@@ -42,8 +42,8 @@
|
|
|
42
42
|
},
|
|
43
43
|
"authUrl": {
|
|
44
44
|
"type": "string",
|
|
45
|
-
"examples": ["https://
|
|
46
|
-
"description": "Your PropelAuth authUrl. For example, `https://
|
|
45
|
+
"examples": ["https://12345678.propelauthtest.com"],
|
|
46
|
+
"description": "Your PropelAuth authUrl. For example, `https://12345678.propelauthtest.com`."
|
|
47
47
|
},
|
|
48
48
|
"verifierKey": {
|
|
49
49
|
"type": "string",
|
|
@@ -64,7 +64,7 @@
|
|
|
64
64
|
"module": "$import(@zuplo/runtime)",
|
|
65
65
|
"options": {
|
|
66
66
|
"allowUnauthenticatedRequests": false,
|
|
67
|
-
"authUrl": "https://
|
|
67
|
+
"authUrl": "https://12345678.propelauthtest.com",
|
|
68
68
|
"oAuthResourceMetadataEnabled": false,
|
|
69
69
|
"verifierKey": "$env(PROPEL_VERIFIER_KEY)"
|
|
70
70
|
}
|