auth0-deploy-cli 8.39.0 → 8.41.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 (29) hide show
  1. package/CHANGELOG.md +26 -1
  2. package/lib/context/directory/handlers/clientAuthCredentials.d.ts +5 -0
  3. package/lib/context/directory/handlers/clientAuthCredentials.js +13 -0
  4. package/lib/context/directory/handlers/clients.js +15 -0
  5. package/lib/context/directory/handlers/index.js +4 -0
  6. package/lib/context/directory/handlers/rateLimitPolicies.d.ts +6 -0
  7. package/lib/context/directory/handlers/rateLimitPolicies.js +53 -0
  8. package/lib/context/yaml/handlers/clientAuthCredentials.d.ts +5 -0
  9. package/lib/context/yaml/handlers/clientAuthCredentials.js +13 -0
  10. package/lib/context/yaml/handlers/clients.js +15 -0
  11. package/lib/context/yaml/handlers/index.js +4 -0
  12. package/lib/context/yaml/handlers/rateLimitPolicies.d.ts +6 -0
  13. package/lib/context/yaml/handlers/rateLimitPolicies.js +27 -0
  14. package/lib/tools/auth0/handlers/clientAuthCredentials.d.ts +26 -0
  15. package/lib/tools/auth0/handlers/clientAuthCredentials.js +216 -0
  16. package/lib/tools/auth0/handlers/clientAuthCredentialsPre.d.ts +37 -0
  17. package/lib/tools/auth0/handlers/clientAuthCredentialsPre.js +118 -0
  18. package/lib/tools/auth0/handlers/clients.js +38 -1
  19. package/lib/tools/auth0/handlers/eventStreams.js +10 -2
  20. package/lib/tools/auth0/handlers/index.js +8 -0
  21. package/lib/tools/auth0/handlers/organizations.d.ts +4 -0
  22. package/lib/tools/auth0/handlers/organizations.js +4 -0
  23. package/lib/tools/auth0/handlers/prompts.js +1 -1
  24. package/lib/tools/auth0/handlers/rateLimitPolicies.d.ts +81 -0
  25. package/lib/tools/auth0/handlers/rateLimitPolicies.js +203 -0
  26. package/lib/tools/constants.d.ts +1 -0
  27. package/lib/tools/constants.js +1 -0
  28. package/lib/types.d.ts +3 -1
  29. package/package.json +2 -2
package/CHANGELOG.md CHANGED
@@ -7,6 +7,24 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
7
7
 
8
8
  ## [Unreleased]
9
9
 
10
+ ## [8.41.0] - 2026-07-16
11
+
12
+ ### Added
13
+
14
+ - Add `third_party_client_access` support for organizations. [#1421]
15
+
16
+ ## [8.40.0] - 2026-07-09
17
+
18
+ ### Added
19
+
20
+ - Add client credential lifecycle management for Private Key JWT and mTLS authentication methods. [#1417]
21
+ - Add Rate Limit Policies (EA) support. [#1395]
22
+
23
+ ### Fixed
24
+
25
+ - Preserve `false` value for `default_head_tags_disabled` in screen renderer update. [#1416]
26
+ - Skip destination update for action event streams as the destination type cannot be changed after creation. [#1425]
27
+
10
28
  ## [8.39.0] - 2026-06-30
11
29
 
12
30
  ### Added
@@ -1842,6 +1860,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
1842
1860
  [#1389]: https://github.com/auth0/auth0-deploy-cli/issues/1389
1843
1861
  [#1391]: https://github.com/auth0/auth0-deploy-cli/issues/1391
1844
1862
  [#1392]: https://github.com/auth0/auth0-deploy-cli/issues/1392
1863
+ [#1395]: https://github.com/auth0/auth0-deploy-cli/issues/1395
1845
1864
  [#1396]: https://github.com/auth0/auth0-deploy-cli/issues/1396
1846
1865
  [#1398]: https://github.com/auth0/auth0-deploy-cli/issues/1398
1847
1866
  [#1400]: https://github.com/auth0/auth0-deploy-cli/issues/1400
@@ -1854,7 +1873,13 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
1854
1873
  [#1409]: https://github.com/auth0/auth0-deploy-cli/issues/1409
1855
1874
  [#1411]: https://github.com/auth0/auth0-deploy-cli/issues/1411
1856
1875
  [#1412]: https://github.com/auth0/auth0-deploy-cli/issues/1412
1857
- [Unreleased]: https://github.com/auth0/auth0-deploy-cli/compare/v8.39.0...HEAD
1876
+ [#1416]: https://github.com/auth0/auth0-deploy-cli/issues/1416
1877
+ [#1417]: https://github.com/auth0/auth0-deploy-cli/issues/1417
1878
+ [#1421]: https://github.com/auth0/auth0-deploy-cli/issues/1421
1879
+ [#1425]: https://github.com/auth0/auth0-deploy-cli/issues/1425
1880
+ [Unreleased]: https://github.com/auth0/auth0-deploy-cli/compare/v8.41.0...HEAD
1881
+ [8.41.0]: https://github.com/auth0/auth0-deploy-cli/compare/v8.40.0...v8.41.0
1882
+ [8.40.0]: https://github.com/auth0/auth0-deploy-cli/compare/v8.39.0...v8.40.0
1858
1883
  [8.39.0]: https://github.com/auth0/auth0-deploy-cli/compare/v8.38.0...v8.39.0
1859
1884
  [8.38.0]: https://github.com/auth0/auth0-deploy-cli/compare/v8.37.0...v8.38.0
1860
1885
  [8.37.0]: https://github.com/auth0/auth0-deploy-cli/compare/v8.36.0...v8.37.0
@@ -0,0 +1,5 @@
1
+ import { DirectoryHandler } from '.';
2
+ import { ParsedAsset } from '../../../types';
3
+ type ParsedClientAuthCredentials = ParsedAsset<'clientAuthCredentials', null>;
4
+ declare const clientAuthCredentialsHandler: DirectoryHandler<ParsedClientAuthCredentials>;
5
+ export default clientAuthCredentialsHandler;
@@ -0,0 +1,13 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ function parse(_context) {
4
+ return { clientAuthCredentials: null };
5
+ }
6
+ async function dump(_context) {
7
+ // Credentials are embedded inside each client's JSON file — nothing to dump separately.
8
+ }
9
+ const clientAuthCredentialsHandler = {
10
+ parse,
11
+ dump,
12
+ };
13
+ exports.default = clientAuthCredentialsHandler;
@@ -106,6 +106,21 @@ async function dump(context) {
106
106
  organization_require_behavior: client.organization_require_behavior,
107
107
  };
108
108
  }
109
+ else {
110
+ // strip id-only credentials and remove client_authentication_methods entirely
111
+ // if no named credentials remain — an absent field is treated as deletion on deploy
112
+ if (client.client_authentication_methods) {
113
+ Object.values(client.client_authentication_methods).forEach((method) => {
114
+ if (method?.credentials) {
115
+ method.credentials = method.credentials.filter((c) => c.name);
116
+ }
117
+ });
118
+ const hasAnyCredentials = Object.values(client.client_authentication_methods).some((method) => method?.credentials?.length > 0);
119
+ if (!hasAnyCredentials) {
120
+ delete client.client_authentication_methods;
121
+ }
122
+ }
123
+ }
109
124
  (0, utils_1.dumpJSON)(clientFile, (0, utils_1.clearClientArrays)(client));
110
125
  });
111
126
  }
@@ -43,7 +43,9 @@ const userAttributeProfiles_1 = __importDefault(require("./userAttributeProfiles
43
43
  const connectionProfiles_1 = __importDefault(require("./connectionProfiles"));
44
44
  const tokenExchangeProfiles_1 = __importDefault(require("./tokenExchangeProfiles"));
45
45
  const supplementalSignals_1 = __importDefault(require("./supplementalSignals"));
46
+ const rateLimitPolicies_1 = __importDefault(require("./rateLimitPolicies"));
46
47
  const eventStreams_1 = __importDefault(require("./eventStreams"));
48
+ const clientAuthCredentials_1 = __importDefault(require("./clientAuthCredentials"));
47
49
  const selfServiceProfiles_1 = __importDefault(require("./selfServiceProfiles"));
48
50
  const directoryHandlers = {
49
51
  rules: rules_1.default,
@@ -87,6 +89,8 @@ const directoryHandlers = {
87
89
  connectionProfiles: connectionProfiles_1.default,
88
90
  tokenExchangeProfiles: tokenExchangeProfiles_1.default,
89
91
  supplementalSignals: supplementalSignals_1.default,
92
+ rateLimitPolicies: rateLimitPolicies_1.default,
90
93
  eventStreams: eventStreams_1.default,
94
+ clientAuthCredentials: clientAuthCredentials_1.default,
91
95
  };
92
96
  exports.default = directoryHandlers;
@@ -0,0 +1,6 @@
1
+ import { DirectoryHandler } from '.';
2
+ import { ParsedAsset } from '../../../types';
3
+ import { RateLimitPolicy } from '../../../tools/auth0/handlers/rateLimitPolicies';
4
+ type ParsedRateLimitPolicies = ParsedAsset<'rateLimitPolicies', RateLimitPolicy[]>;
5
+ declare const rateLimitPoliciesHandler: DirectoryHandler<ParsedRateLimitPolicies>;
6
+ export default rateLimitPoliciesHandler;
@@ -0,0 +1,53 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ const path_1 = __importDefault(require("path"));
7
+ const fs_extra_1 = __importDefault(require("fs-extra"));
8
+ const tools_1 = require("../../../tools");
9
+ const utils_1 = require("../../../utils");
10
+ function parse(context) {
11
+ const rateLimitPoliciesDirectory = path_1.default.join(context.filePath, tools_1.constants.RATE_LIMIT_POLICIES_DIRECTORY);
12
+ if (!(0, utils_1.existsMustBeDir)(rateLimitPoliciesDirectory))
13
+ return { rateLimitPolicies: null }; // Skip
14
+ const foundFiles = (0, utils_1.getFiles)(rateLimitPoliciesDirectory, ['.json']);
15
+ const rateLimitPolicies = foundFiles
16
+ .map((f) => (0, utils_1.loadJSON)(f, {
17
+ mappings: context.mappings,
18
+ disableKeywordReplacement: context.disableKeywordReplacement,
19
+ }))
20
+ .filter((p) => Object.keys(p).length > 0);
21
+ return { rateLimitPolicies };
22
+ }
23
+ async function dump(context) {
24
+ const { rateLimitPolicies } = context.assets;
25
+ if (!rateLimitPolicies)
26
+ return; // Skip, nothing to dump
27
+ const rateLimitPoliciesDirectory = path_1.default.join(context.filePath, tools_1.constants.RATE_LIMIT_POLICIES_DIRECTORY);
28
+ fs_extra_1.default.ensureDirSync(rateLimitPoliciesDirectory);
29
+ const removeKeysFromOutput = ['id', 'created_at', 'updated_at'];
30
+ const expectedFiles = new Set();
31
+ rateLimitPolicies.forEach((policy) => {
32
+ const policyToWrite = { ...policy };
33
+ removeKeysFromOutput.forEach((key) => {
34
+ delete policyToWrite[key];
35
+ });
36
+ const fileName = (0, utils_1.sanitize)(policy.consumer_selector);
37
+ const filePath = path_1.default.join(rateLimitPoliciesDirectory, `${fileName}.json`);
38
+ expectedFiles.add(`${fileName}.json`);
39
+ (0, utils_1.dumpJSON)(filePath, policyToWrite);
40
+ });
41
+ // Remove files for policies that no longer exist in the tenant
42
+ for (const existing of fs_extra_1.default.readdirSync(rateLimitPoliciesDirectory)) {
43
+ const fullPath = path_1.default.join(rateLimitPoliciesDirectory, existing);
44
+ if (fs_extra_1.default.statSync(fullPath).isFile() && !expectedFiles.has(existing)) {
45
+ fs_extra_1.default.removeSync(fullPath);
46
+ }
47
+ }
48
+ }
49
+ const rateLimitPoliciesHandler = {
50
+ parse,
51
+ dump,
52
+ };
53
+ exports.default = rateLimitPoliciesHandler;
@@ -0,0 +1,5 @@
1
+ import { YAMLHandler } from '.';
2
+ import { ParsedAsset } from '../../../types';
3
+ type ParsedClientAuthCredentials = ParsedAsset<'clientAuthCredentials', null>;
4
+ declare const clientAuthCredentialsHandler: YAMLHandler<ParsedClientAuthCredentials>;
5
+ export default clientAuthCredentialsHandler;
@@ -0,0 +1,13 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ async function parse(_context) {
4
+ return { clientAuthCredentials: null };
5
+ }
6
+ async function dump(_context) {
7
+ return { clientAuthCredentials: null };
8
+ }
9
+ const clientAuthCredentialsHandler = {
10
+ parse,
11
+ dump,
12
+ };
13
+ exports.default = clientAuthCredentialsHandler;
@@ -99,6 +99,21 @@ async function dump(context) {
99
99
  organization_require_behavior: client.organization_require_behavior,
100
100
  };
101
101
  }
102
+ else {
103
+ // strip id-only credentials and remove client_authentication_methods entirely
104
+ // if no named credentials remain — an absent field is treated as deletion on deploy
105
+ if (client.client_authentication_methods) {
106
+ Object.values(client.client_authentication_methods).forEach((method) => {
107
+ if (method?.credentials) {
108
+ method.credentials = method.credentials.filter((c) => c.name);
109
+ }
110
+ });
111
+ const hasAnyCredentials = Object.values(client.client_authentication_methods).some((method) => method?.credentials?.length > 0);
112
+ if (!hasAnyCredentials) {
113
+ delete client.client_authentication_methods;
114
+ }
115
+ }
116
+ }
102
117
  return (0, utils_1.clearClientArrays)(client);
103
118
  }),
104
119
  ],
@@ -43,7 +43,9 @@ const userAttributeProfiles_1 = __importDefault(require("./userAttributeProfiles
43
43
  const connectionProfiles_1 = __importDefault(require("./connectionProfiles"));
44
44
  const tokenExchangeProfiles_1 = __importDefault(require("./tokenExchangeProfiles"));
45
45
  const supplementalSignals_1 = __importDefault(require("./supplementalSignals"));
46
+ const rateLimitPolicies_1 = __importDefault(require("./rateLimitPolicies"));
46
47
  const eventStreams_1 = __importDefault(require("./eventStreams"));
48
+ const clientAuthCredentials_1 = __importDefault(require("./clientAuthCredentials"));
47
49
  const selfServiceProfiles_1 = __importDefault(require("./selfServiceProfiles"));
48
50
  const yamlHandlers = {
49
51
  rules: rules_1.default,
@@ -87,6 +89,8 @@ const yamlHandlers = {
87
89
  connectionProfiles: connectionProfiles_1.default,
88
90
  tokenExchangeProfiles: tokenExchangeProfiles_1.default,
89
91
  supplementalSignals: supplementalSignals_1.default,
92
+ rateLimitPolicies: rateLimitPolicies_1.default,
90
93
  eventStreams: eventStreams_1.default,
94
+ clientAuthCredentials: clientAuthCredentials_1.default,
91
95
  };
92
96
  exports.default = yamlHandlers;
@@ -0,0 +1,6 @@
1
+ import { YAMLHandler } from '.';
2
+ import { ParsedAsset } from '../../../types';
3
+ import { RateLimitPolicy } from '../../../tools/auth0/handlers/rateLimitPolicies';
4
+ type ParsedRateLimitPolicies = ParsedAsset<'rateLimitPolicies', RateLimitPolicy[]>;
5
+ declare const rateLimitPoliciesHandler: YAMLHandler<ParsedRateLimitPolicies>;
6
+ export default rateLimitPoliciesHandler;
@@ -0,0 +1,27 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ async function parse(context) {
4
+ const { rateLimitPolicies } = context.assets;
5
+ if (!rateLimitPolicies)
6
+ return { rateLimitPolicies: null };
7
+ return { rateLimitPolicies };
8
+ }
9
+ async function dump(context) {
10
+ const { rateLimitPolicies } = context.assets;
11
+ if (!rateLimitPolicies)
12
+ return { rateLimitPolicies: null };
13
+ const removeKeysFromOutput = ['id', 'created_at', 'updated_at'];
14
+ const cleaned = rateLimitPolicies.map((policy) => {
15
+ const policyToWrite = { ...policy };
16
+ removeKeysFromOutput.forEach((key) => {
17
+ delete policyToWrite[key];
18
+ });
19
+ return policyToWrite;
20
+ });
21
+ return { rateLimitPolicies: cleaned };
22
+ }
23
+ const rateLimitPoliciesHandler = {
24
+ parse,
25
+ dump,
26
+ };
27
+ exports.default = rateLimitPoliciesHandler;
@@ -0,0 +1,26 @@
1
+ import { Assets, Auth0APIClient } from '../../../types';
2
+ import { ConfigFunction } from '../../../configFactory';
3
+ export declare const schema: {
4
+ type: string;
5
+ items: {
6
+ type: string;
7
+ };
8
+ };
9
+ export default class ClientAuthCredentialsHandler {
10
+ client: Auth0APIClient;
11
+ config: ConfigFunction;
12
+ type: string;
13
+ existing: null;
14
+ constructor({ client, config }: {
15
+ client: Auth0APIClient;
16
+ config: ConfigFunction;
17
+ });
18
+ getType(): Promise<null>;
19
+ load(): Promise<{
20
+ [x: string]: null;
21
+ }>;
22
+ validate(): Promise<null>;
23
+ processChanges(assets: Assets): Promise<void>;
24
+ private inferCredentialType;
25
+ private inferMethodFromType;
26
+ }
@@ -0,0 +1,216 @@
1
+ "use strict";
2
+ var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
3
+ var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
4
+ if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
5
+ else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
6
+ return c > 3 && r && Object.defineProperty(target, key, r), r;
7
+ };
8
+ var __importDefault = (this && this.__importDefault) || function (mod) {
9
+ return (mod && mod.__esModule) ? mod : { "default": mod };
10
+ };
11
+ Object.defineProperty(exports, "__esModule", { value: true });
12
+ exports.schema = void 0;
13
+ const default_1 = require("./default");
14
+ const client_1 = require("../client");
15
+ const logger_1 = __importDefault(require("../../../logger"));
16
+ exports.schema = {
17
+ type: 'array',
18
+ items: { type: 'object' },
19
+ };
20
+ const CREDENTIAL_TYPE_TO_METHOD = {
21
+ public_key: 'private_key_jwt',
22
+ x509_cert: 'self_signed_tls_client_auth',
23
+ cert_subject_dn: 'tls_client_auth',
24
+ };
25
+ class ClientAuthCredentialsHandler {
26
+ constructor({ client, config }) {
27
+ this.type = 'clientAuthCredentials';
28
+ this.existing = null;
29
+ this.client = client;
30
+ this.config = config;
31
+ }
32
+ async getType() {
33
+ return null;
34
+ }
35
+ async load() {
36
+ logger_1.default.info(`Retrieving ${this.type} data from Auth0`);
37
+ return { [this.type]: null };
38
+ }
39
+ async validate() {
40
+ return null;
41
+ }
42
+ async processChanges(assets) {
43
+ const { clients } = assets;
44
+ if (!clients)
45
+ return;
46
+ const allowDelete = this.config('AUTH0_ALLOW_DELETE') === true || this.config('AUTH0_ALLOW_DELETE') === 'true';
47
+ // Only process clients that have client_authentication_methods in config.
48
+ // Full deletion (absent field) is handled by ClientAuthCredentialsPreHandler at order 40,
49
+ // before clients.ts runs. This handler only manages create and partial delete.
50
+ const clientsWithCam = clients.filter((c) => c.client_authentication_methods !== undefined);
51
+ if (clientsWithCam.length === 0)
52
+ return;
53
+ // In directory mode client_id is stripped. Resolve names for PKI clients only.
54
+ const needsNameResolution = clientsWithCam.some((c) => !c.client_id);
55
+ let clientIdByName = new Map();
56
+ if (needsNameResolution) {
57
+ const existingClients = await (0, client_1.paginate)(this.client.clients.list, {
58
+ paginate: true,
59
+ is_global: false,
60
+ });
61
+ clientIdByName = new Map(existingClients.map((c) => [c.name, c.client_id]));
62
+ }
63
+ for (const client of clientsWithCam) {
64
+ const clientId = client.client_id || (client.name && clientIdByName.get(client.name));
65
+ if (!clientId)
66
+ continue;
67
+ client.client_id = clientId;
68
+ const clientName = client.name || clientId;
69
+ // Collect all desired credentials across all auth methods (only pem-bearing entries)
70
+ const desired = [];
71
+ if (client.client_authentication_methods) {
72
+ for (const [methodKey, methodVal] of Object.entries(client.client_authentication_methods)) {
73
+ const credentials = methodVal?.credentials || [];
74
+ for (const cred of credentials) {
75
+ if (!cred.pem)
76
+ continue;
77
+ desired.push({
78
+ name: cred.name,
79
+ pem: cred.pem,
80
+ credential_type: cred.credential_type || this.inferCredentialType(methodKey),
81
+ method: methodKey,
82
+ });
83
+ }
84
+ }
85
+ }
86
+ // pem is the opt-in signal: present field with no pem = skip (safe export→deploy);
87
+ // absent field = fall through to delete path (intentional removal).
88
+ if (desired.length === 0 && client.client_authentication_methods)
89
+ continue;
90
+ let existing = [];
91
+ try {
92
+ existing = (await this.client.clients.credentials.list(clientId));
93
+ }
94
+ catch (err) {
95
+ logger_1.default.warn(`clientAuthCredentials: failed to list credentials for client "${clientName}": ${err}`);
96
+ continue;
97
+ }
98
+ // No credentials in Auth0 and none desired — nothing to do.
99
+ if (existing.length === 0 && desired.length === 0)
100
+ continue;
101
+ // Warn if duplicate names exist in Auth0 — we can't match safely
102
+ const existingNames = existing.map((c) => c.name);
103
+ const duplicateNames = existingNames.filter((n, i) => existingNames.indexOf(n) !== i);
104
+ if (duplicateNames.length > 0) {
105
+ logger_1.default.warn(`clientAuthCredentials: client "${clientName}" has duplicate credential names in Auth0 [${duplicateNames.join(', ')}] — skipping credential reconciliation for this client`);
106
+ continue;
107
+ }
108
+ const existingByName = new Map(existing.map((c) => [c.name, c]));
109
+ const desiredNames = new Set(desired.map((d) => d.name));
110
+ const toCreate = desired.filter((d) => !existingByName.has(d.name));
111
+ const toDelete = existing.filter((e) => !desiredNames.has(e.name));
112
+ // Creates first — Auth0 allows max 2 credentials; both must exist simultaneously during rotation
113
+ // Track name→id so we can correctly attribute each created credential to its method later.
114
+ const createdIdByName = new Map();
115
+ for (const cred of toCreate) {
116
+ try {
117
+ const created = await this.client.clients.credentials.create(clientId, {
118
+ name: cred.name,
119
+ pem: cred.pem,
120
+ credential_type: cred.credential_type,
121
+ });
122
+ logger_1.default.info(`clientAuthCredentials: created credential "${cred.name}" on client "${clientName}"`);
123
+ createdIdByName.set(cred.name, created.id);
124
+ }
125
+ catch (err) {
126
+ logger_1.default.warn(`clientAuthCredentials: failed to create credential "${cred.name}" on client "${clientName}": ${err}`);
127
+ }
128
+ }
129
+ // Re-wire client_authentication_methods with final IDs (kept + newly created).
130
+ // This must happen BEFORE deletes — Auth0 rejects deleting a credential that
131
+ // is still referenced in client_authentication_methods.
132
+ const keptIds = existing.filter((e) => desiredNames.has(e.name)).map((e) => e.id);
133
+ const createdIds = [...createdIdByName.values()];
134
+ const finalIds = [...keptIds, ...createdIds];
135
+ let updatedAuthMethods = null;
136
+ if (finalIds.length > 0) {
137
+ // Build method→ids map. For kept credentials use Auth0's stored type to infer method;
138
+ // for created credentials use the method from the user's config entry (by name).
139
+ const methodToIds = {};
140
+ for (const id of finalIds) {
141
+ const fromExisting = existing.find((e) => e.id === id);
142
+ const createdName = [...createdIdByName.entries()].find(([, cid]) => cid === id)?.[0];
143
+ const fromDesired = createdName ? desired.find((d) => d.name === createdName) : undefined;
144
+ const methodKey = (fromExisting && this.inferMethodFromType(fromExisting.credential_type)) ||
145
+ (fromDesired && fromDesired.method) ||
146
+ Object.keys(client.client_authentication_methods)[0];
147
+ if (!methodToIds[methodKey])
148
+ methodToIds[methodKey] = [];
149
+ methodToIds[methodKey].push(id);
150
+ }
151
+ updatedAuthMethods = {};
152
+ for (const [methodKey, ids] of Object.entries(methodToIds)) {
153
+ updatedAuthMethods[methodKey] = { credentials: ids.map((id) => ({ id })) };
154
+ }
155
+ }
156
+ // Always update client_authentication_methods before deletes:
157
+ // - When finalIds > 0: re-wire to the remaining credentials
158
+ // - When finalIds === 0 but toDelete > 0: set to null so Auth0 de-references them first
159
+ if (finalIds.length > 0 || toDelete.length > 0) {
160
+ try {
161
+ const payload = {
162
+ client_authentication_methods: updatedAuthMethods ?? null,
163
+ };
164
+ // Auth0 requires token_endpoint_auth_method: null when setting client_authentication_methods,
165
+ // and a non-null value when clearing it.
166
+ if (updatedAuthMethods) {
167
+ payload.token_endpoint_auth_method = null;
168
+ }
169
+ else {
170
+ payload.token_endpoint_auth_method =
171
+ client.token_endpoint_auth_method || 'client_secret_post';
172
+ }
173
+ await this.client.clients.update(clientId, payload);
174
+ logger_1.default.info(`clientAuthCredentials: updated client_authentication_methods on client "${clientName}"`);
175
+ }
176
+ catch (err) {
177
+ logger_1.default.warn(`clientAuthCredentials: failed to update client_authentication_methods on client "${clientName}": ${err}`);
178
+ }
179
+ }
180
+ // Deletes last — after client_authentication_methods no longer references them
181
+ if (toDelete.length > 0) {
182
+ if (!allowDelete) {
183
+ logger_1.default.warn(`clientAuthCredentials: the following credentials on client "${clientName}" would be deleted but AUTH0_ALLOW_DELETE is not set:\n${toDelete
184
+ .map((c) => ` ${c.name} (${c.id})`)
185
+ .join('\n')}`);
186
+ }
187
+ else {
188
+ for (const cred of toDelete) {
189
+ try {
190
+ await this.client.clients.credentials.delete(clientId, cred.id);
191
+ logger_1.default.info(`clientAuthCredentials: deleted credential "${cred.name}" on client "${clientName}"`);
192
+ }
193
+ catch (err) {
194
+ logger_1.default.warn(`clientAuthCredentials: failed to delete credential "${cred.name}" on client "${clientName}": ${err}`);
195
+ }
196
+ }
197
+ }
198
+ }
199
+ }
200
+ }
201
+ inferCredentialType(methodKey) {
202
+ const map = {
203
+ private_key_jwt: 'public_key',
204
+ self_signed_tls_client_auth: 'x509_cert',
205
+ tls_client_auth: 'cert_subject_dn',
206
+ };
207
+ return map[methodKey] || 'public_key';
208
+ }
209
+ inferMethodFromType(credentialType) {
210
+ return CREDENTIAL_TYPE_TO_METHOD[credentialType] || 'private_key_jwt';
211
+ }
212
+ }
213
+ exports.default = ClientAuthCredentialsHandler;
214
+ __decorate([
215
+ (0, default_1.order)('70')
216
+ ], ClientAuthCredentialsHandler.prototype, "processChanges", null);
@@ -0,0 +1,37 @@
1
+ import { Assets, Auth0APIClient } from '../../../types';
2
+ import { ConfigFunction } from '../../../configFactory';
3
+ export declare const schema: {
4
+ type: string;
5
+ items: {
6
+ type: string;
7
+ };
8
+ };
9
+ /**
10
+ * Handles full credential deletion BEFORE clients.ts (order 50) patches the client.
11
+ *
12
+ * Auth0 rejects a client PATCH containing token_endpoint_auth_method while that client still
13
+ * has active credentials. By running at order 40, this handler clears credentials (and
14
+ * client_authentication_methods) for any client where the field is absent from config, so
15
+ * that clients.ts can safely include token_endpoint_auth_method in its PATCH.
16
+ *
17
+ * Partial deletion (some credentials removed, others kept) is handled by
18
+ * ClientAuthCredentialsHandler at order 70, because those clients still have
19
+ * client_authentication_methods present in config and clients.ts strips token_endpoint_auth_method
20
+ * for them anyway.
21
+ */
22
+ export default class ClientAuthCredentialsPreHandler {
23
+ client: Auth0APIClient;
24
+ config: ConfigFunction;
25
+ type: string;
26
+ existing: null;
27
+ constructor({ client, config }: {
28
+ client: Auth0APIClient;
29
+ config: ConfigFunction;
30
+ });
31
+ getType(): Promise<null>;
32
+ load(): Promise<{
33
+ [x: string]: null;
34
+ }>;
35
+ validate(): Promise<null>;
36
+ processChanges(assets: Assets): Promise<void>;
37
+ }
@@ -0,0 +1,118 @@
1
+ "use strict";
2
+ var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
3
+ var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
4
+ if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
5
+ else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
6
+ return c > 3 && r && Object.defineProperty(target, key, r), r;
7
+ };
8
+ var __importDefault = (this && this.__importDefault) || function (mod) {
9
+ return (mod && mod.__esModule) ? mod : { "default": mod };
10
+ };
11
+ Object.defineProperty(exports, "__esModule", { value: true });
12
+ exports.schema = void 0;
13
+ const default_1 = require("./default");
14
+ const client_1 = require("../client");
15
+ const logger_1 = __importDefault(require("../../../logger"));
16
+ exports.schema = {
17
+ type: 'array',
18
+ items: { type: 'object' },
19
+ };
20
+ /**
21
+ * Handles full credential deletion BEFORE clients.ts (order 50) patches the client.
22
+ *
23
+ * Auth0 rejects a client PATCH containing token_endpoint_auth_method while that client still
24
+ * has active credentials. By running at order 40, this handler clears credentials (and
25
+ * client_authentication_methods) for any client where the field is absent from config, so
26
+ * that clients.ts can safely include token_endpoint_auth_method in its PATCH.
27
+ *
28
+ * Partial deletion (some credentials removed, others kept) is handled by
29
+ * ClientAuthCredentialsHandler at order 70, because those clients still have
30
+ * client_authentication_methods present in config and clients.ts strips token_endpoint_auth_method
31
+ * for them anyway.
32
+ */
33
+ class ClientAuthCredentialsPreHandler {
34
+ constructor({ client, config }) {
35
+ // Same type as ClientAuthCredentialsHandler so AUTH0_EXCLUDED / AUTH0_INCLUDED_ONLY
36
+ // applies to both handlers together without needing a separate AssetTypes entry.
37
+ this.type = 'clientAuthCredentials';
38
+ this.existing = null;
39
+ this.client = client;
40
+ this.config = config;
41
+ }
42
+ async getType() {
43
+ return null;
44
+ }
45
+ async load() {
46
+ return { [this.type]: null };
47
+ }
48
+ async validate() {
49
+ return null;
50
+ }
51
+ async processChanges(assets) {
52
+ const { clients } = assets;
53
+ if (!clients)
54
+ return;
55
+ const allowDelete = this.config('AUTH0_ALLOW_DELETE') === true || this.config('AUTH0_ALLOW_DELETE') === 'true';
56
+ // When allowDelete is false no deletion will happen — skip entirely to avoid
57
+ // unnecessary GET /credentials calls for every client.
58
+ if (!allowDelete)
59
+ return;
60
+ // Only act on clients where client_authentication_methods is absent from config.
61
+ // Absent = intentional full deletion. Clients with the field present (including partial
62
+ // deletion) are fully handled by ClientAuthCredentialsHandler at order 70.
63
+ const deletionCandidates = clients.filter((c) => c.client_authentication_methods === undefined);
64
+ if (deletionCandidates.length === 0)
65
+ return;
66
+ // In directory mode client_id is stripped. Resolve names once for all candidates.
67
+ const needsNameResolution = deletionCandidates.some((c) => !c.client_id);
68
+ let clientIdByName = new Map();
69
+ if (needsNameResolution) {
70
+ const existingClients = await (0, client_1.paginate)(this.client.clients.list, {
71
+ paginate: true,
72
+ is_global: false,
73
+ });
74
+ clientIdByName = new Map(existingClients.map((c) => [c.name, c.client_id]));
75
+ }
76
+ for (const client of deletionCandidates) {
77
+ const clientId = client.client_id || (client.name && clientIdByName.get(client.name));
78
+ if (!clientId)
79
+ continue;
80
+ const clientName = client.name || clientId;
81
+ let existing = [];
82
+ try {
83
+ existing = (await this.client.clients.credentials.list(clientId));
84
+ }
85
+ catch (err) {
86
+ logger_1.default.warn(`clientAuthCredentials: failed to list credentials for client "${clientName}": ${err}`);
87
+ continue;
88
+ }
89
+ if (existing.length === 0)
90
+ continue;
91
+ // De-reference credentials from client_authentication_methods before deleting them —
92
+ // Auth0 rejects deleting a credential that is still referenced.
93
+ try {
94
+ await this.client.clients.update(clientId, {
95
+ client_authentication_methods: null,
96
+ token_endpoint_auth_method: client.token_endpoint_auth_method || 'client_secret_post',
97
+ });
98
+ }
99
+ catch (err) {
100
+ logger_1.default.warn(`clientAuthCredentials: failed to clear client_authentication_methods on client "${clientName}": ${err}`);
101
+ continue;
102
+ }
103
+ for (const cred of existing) {
104
+ try {
105
+ await this.client.clients.credentials.delete(clientId, cred.id);
106
+ logger_1.default.info(`clientAuthCredentials: deleted credential "${cred.name}" on client "${clientName}"`);
107
+ }
108
+ catch (err) {
109
+ logger_1.default.warn(`clientAuthCredentials: failed to delete credential "${cred.name}" on client "${clientName}": ${err}`);
110
+ }
111
+ }
112
+ }
113
+ }
114
+ }
115
+ exports.default = ClientAuthCredentialsPreHandler;
116
+ __decorate([
117
+ (0, default_1.order)('40')
118
+ ], ClientAuthCredentialsPreHandler.prototype, "processChanges", null);
@@ -566,6 +566,17 @@ class ClientHandler extends default_1.default {
566
566
  delete item.refresh_token;
567
567
  }
568
568
  }
569
+ // Strip client_authentication_methods — the clientAuthCredentials handler (order 70)
570
+ // owns this field entirely. Auth0 rejects credential objects with name/credential_type in PATCH.
571
+ // Strip token_endpoint_auth_method only when client_authentication_methods is present in config:
572
+ // Auth0 rejects it in PATCH while a client has active credentials. For these clients the
573
+ // clientAuthCredentials handler (order 70) owns token_endpoint_auth_method too.
574
+ // For clients without client_authentication_methods, credentials were already cleared by
575
+ // clientAuthCredentialsPre (order 40), so token_endpoint_auth_method passes through safely.
576
+ if (item.client_authentication_methods) {
577
+ delete item.token_endpoint_auth_method;
578
+ }
579
+ delete item.client_authentication_methods;
569
580
  return item;
570
581
  });
571
582
  };
@@ -587,7 +598,33 @@ class ClientHandler extends default_1.default {
587
598
  is_global: false,
588
599
  ...((0, utils_1.shouldExcludeThirdPartyClients)(this.config) && { is_first_party: true }),
589
600
  });
590
- this.existing = createClientSanitizer(clients).sanitizeCrossOriginAuth(false).get();
601
+ const sanitized = createClientSanitizer(clients).sanitizeCrossOriginAuth(false).get();
602
+ // Enrich credential stubs with name and credential_type for export.
603
+ // Auth0 does not return pem on read — it is never exported.
604
+ await Promise.all(sanitized.map(async (client) => {
605
+ if (!client.client_authentication_methods)
606
+ return;
607
+ try {
608
+ const creds = await this.client.clients.credentials.list(client.client_id);
609
+ const credMap = new Map(creds.map((c) => [c.id, c]));
610
+ Object.values(client.client_authentication_methods).forEach((method) => {
611
+ if (method?.credentials) {
612
+ method.credentials = method.credentials
613
+ .map((stub) => {
614
+ const full = credMap.get(stub.id);
615
+ if (!full?.name)
616
+ return null;
617
+ return { name: full.name, credential_type: full.credential_type };
618
+ })
619
+ .filter(Boolean);
620
+ }
621
+ });
622
+ }
623
+ catch (_) {
624
+ // leave stubs as-is if the credentials API call fails
625
+ }
626
+ }));
627
+ this.existing = sanitized;
591
628
  return this.existing;
592
629
  }
593
630
  isCimdClient(client) {
@@ -38,10 +38,14 @@ var __importStar = (this && this.__importStar) || (function () {
38
38
  return result;
39
39
  };
40
40
  })();
41
+ var __importDefault = (this && this.__importDefault) || function (mod) {
42
+ return (mod && mod.__esModule) ? mod : { "default": mod };
43
+ };
41
44
  Object.defineProperty(exports, "__esModule", { value: true });
42
45
  exports.schema = void 0;
43
46
  const default_1 = __importStar(require("./default"));
44
47
  const client_1 = require("../client");
48
+ const logger_1 = __importDefault(require("../../../logger"));
45
49
  exports.schema = {
46
50
  type: 'array',
47
51
  items: {
@@ -161,8 +165,12 @@ class EventStreamsHandler extends default_1.default {
161
165
  create: changesResponse.create.map((stream) => this.resolveActionId(stream)),
162
166
  update: changesResponse.update.map((stream) => {
163
167
  const resolved = this.resolveActionId(stream);
164
- // EventBridge destinations cannot be patched — the API rejects destination on PATCH
165
- if (resolved.destination?.type === 'eventbridge') {
168
+ // A destination's type cannot be changed once an event stream is created. The API
169
+ // rejects the destination on PATCH for eventbridge and action streams, so strip it
170
+ // from the update payload and only apply the other mutable fields.
171
+ if (resolved.destination?.type === 'eventbridge' ||
172
+ resolved.destination?.type === 'action') {
173
+ logger_1.default.info(`Skipping destination update for event stream "${resolved.name}": ${resolved.destination.type} destinations cannot be changed after creation.`);
166
174
  const { destination: _dest, ...rest } = resolved;
167
175
  return rest;
168
176
  }
@@ -74,7 +74,10 @@ const userAttributeProfiles = __importStar(require("./userAttributeProfiles"));
74
74
  const connectionProfiles = __importStar(require("./connectionProfiles"));
75
75
  const tokenExchangeProfiles = __importStar(require("./tokenExchangeProfiles"));
76
76
  const supplementalSignals = __importStar(require("./supplementalSignals"));
77
+ const rateLimitPolicies = __importStar(require("./rateLimitPolicies"));
77
78
  const eventStreams = __importStar(require("./eventStreams"));
79
+ const clientAuthCredentials = __importStar(require("./clientAuthCredentials"));
80
+ const clientAuthCredentialsPre = __importStar(require("./clientAuthCredentialsPre"));
78
81
  const auth0ApiHandlers = {
79
82
  rules,
80
83
  rulesConfigs,
@@ -118,6 +121,11 @@ const auth0ApiHandlers = {
118
121
  connectionProfiles,
119
122
  tokenExchangeProfiles,
120
123
  supplementalSignals,
124
+ rateLimitPolicies,
121
125
  eventStreams,
126
+ clientAuthCredentials,
127
+ // clientAuthCredentialsPre is a deploy-only pre-pass handler (order 40) — not a user-facing
128
+ // asset type so it is not in AssetTypes, but must be registered here to run during deploy.
129
+ ...{ clientAuthCredentialsPre },
122
130
  };
123
131
  exports.default = auth0ApiHandlers; // TODO: apply stronger types to schema properties
@@ -104,6 +104,10 @@ export declare const schema: {
104
104
  required: string[];
105
105
  };
106
106
  };
107
+ third_party_client_access: {
108
+ type: string;
109
+ enum: ("allow" | "block")[];
110
+ };
107
111
  };
108
112
  required: string[];
109
113
  };
@@ -127,6 +127,10 @@ exports.schema = {
127
127
  required: ['domain', 'status'],
128
128
  },
129
129
  },
130
+ third_party_client_access: {
131
+ type: 'string',
132
+ enum: Object.values(auth0_1.Management.OrganizationThirdPartyClientAccessEnum),
133
+ },
130
134
  },
131
135
  required: ['name'],
132
136
  },
@@ -496,7 +496,7 @@ class PromptsHandler extends default_1.default {
496
496
  updatePayload = {
497
497
  ...updatePrams,
498
498
  rendering_mode: auth0_1.Management.AculRenderingModeEnum.Advanced,
499
- default_head_tags_disabled: screenRenderer.default_head_tags_disabled || undefined,
499
+ default_head_tags_disabled: screenRenderer.default_head_tags_disabled ?? undefined,
500
500
  head_tags: screenRenderer.head_tags,
501
501
  };
502
502
  }
@@ -0,0 +1,81 @@
1
+ import { Management } from 'auth0';
2
+ import DefaultAPIHandler from './default';
3
+ import { Asset, Assets, CalculatedChanges } from '../../../types';
4
+ export type RateLimitPolicyConfiguration = Management.RateLimitPolicyConfiguration;
5
+ export type RateLimitPolicy = Management.RateLimitPolicy;
6
+ export declare const schema: {
7
+ type: string;
8
+ items: {
9
+ type: string;
10
+ properties: {
11
+ resource: {
12
+ type: string;
13
+ enum: "oauth_authentication_api"[];
14
+ };
15
+ consumer: {
16
+ type: string;
17
+ enum: "client"[];
18
+ };
19
+ consumer_selector: {
20
+ type: string;
21
+ };
22
+ configuration: {
23
+ type: string;
24
+ oneOf: ({
25
+ required: string[];
26
+ properties: {
27
+ action: {
28
+ type: string;
29
+ enum: string[];
30
+ };
31
+ limit?: undefined;
32
+ redirect_uri?: undefined;
33
+ };
34
+ additionalProperties: boolean;
35
+ } | {
36
+ required: string[];
37
+ properties: {
38
+ action: {
39
+ type: string;
40
+ enum: string[];
41
+ };
42
+ limit: {
43
+ type: string;
44
+ };
45
+ redirect_uri?: undefined;
46
+ };
47
+ additionalProperties: boolean;
48
+ } | {
49
+ required: string[];
50
+ properties: {
51
+ action: {
52
+ type: string;
53
+ enum: string[];
54
+ };
55
+ limit: {
56
+ type: string;
57
+ };
58
+ redirect_uri: {
59
+ type: string;
60
+ };
61
+ };
62
+ additionalProperties: boolean;
63
+ })[];
64
+ };
65
+ };
66
+ required: string[];
67
+ };
68
+ };
69
+ export default class RateLimitPoliciesHandler extends DefaultAPIHandler {
70
+ existing: RateLimitPolicy[] | null;
71
+ constructor(config: DefaultAPIHandler);
72
+ objString(policy: RateLimitPolicy): string;
73
+ getType(): Promise<Asset | null>;
74
+ processChanges(assets: Assets): Promise<void>;
75
+ createRateLimitPolicy(policy: RateLimitPolicy): Promise<RateLimitPolicy>;
76
+ createRateLimitPolicies(creates: CalculatedChanges['create']): Promise<void>;
77
+ updateRateLimitPolicy(policy: RateLimitPolicy): Promise<void>;
78
+ updateRateLimitPolicies(updates: CalculatedChanges['update']): Promise<void>;
79
+ deleteRateLimitPolicy(policy: RateLimitPolicy): Promise<void>;
80
+ deleteRateLimitPolicies(data: Asset[]): Promise<void>;
81
+ }
@@ -0,0 +1,203 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.schema = void 0;
7
+ const auth0_1 = require("auth0");
8
+ const default_1 = __importDefault(require("./default"));
9
+ const client_1 = require("../client");
10
+ const utils_1 = require("../../utils");
11
+ const logger_1 = __importDefault(require("../../../logger"));
12
+ exports.schema = {
13
+ type: 'array',
14
+ items: {
15
+ type: 'object',
16
+ properties: {
17
+ resource: {
18
+ type: 'string',
19
+ enum: Object.values(auth0_1.Management.RateLimitPolicyResourceEnum),
20
+ },
21
+ consumer: {
22
+ type: 'string',
23
+ enum: Object.values(auth0_1.Management.RateLimitPolicyConsumerEnum),
24
+ },
25
+ consumer_selector: {
26
+ type: 'string',
27
+ },
28
+ configuration: {
29
+ type: 'object',
30
+ oneOf: [
31
+ {
32
+ required: ['action'],
33
+ properties: {
34
+ action: { type: 'string', enum: ['allow'] },
35
+ },
36
+ additionalProperties: false,
37
+ },
38
+ {
39
+ required: ['action', 'limit'],
40
+ properties: {
41
+ action: { type: 'string', enum: ['block', 'log'] },
42
+ limit: { type: 'number' },
43
+ },
44
+ additionalProperties: false,
45
+ },
46
+ {
47
+ required: ['action', 'limit', 'redirect_uri'],
48
+ properties: {
49
+ action: { type: 'string', enum: ['redirect'] },
50
+ limit: { type: 'number' },
51
+ redirect_uri: { type: 'string' },
52
+ },
53
+ additionalProperties: false,
54
+ },
55
+ ],
56
+ },
57
+ },
58
+ required: ['resource', 'consumer', 'consumer_selector', 'configuration'],
59
+ },
60
+ };
61
+ class RateLimitPoliciesHandler extends default_1.default {
62
+ constructor(config) {
63
+ super({
64
+ ...config,
65
+ type: 'rateLimitPolicies',
66
+ id: 'id',
67
+ identifiers: ['id', 'consumer_selector'],
68
+ stripCreateFields: ['id', 'created_at', 'updated_at'],
69
+ stripUpdateFields: [
70
+ 'id',
71
+ 'resource',
72
+ 'consumer',
73
+ 'consumer_selector',
74
+ 'created_at',
75
+ 'updated_at',
76
+ ],
77
+ });
78
+ }
79
+ objString(policy) {
80
+ return super.objString({
81
+ consumer_selector: policy.consumer_selector,
82
+ resource: policy.resource,
83
+ });
84
+ }
85
+ async getType() {
86
+ if (this.existing)
87
+ return this.existing;
88
+ try {
89
+ const rateLimitPolicies = await (0, client_1.paginate)(this.client.rateLimitPolicies.list, { checkpoint: true });
90
+ this.existing = rateLimitPolicies;
91
+ return this.existing;
92
+ }
93
+ catch (err) {
94
+ if (err.statusCode === 404 || err.statusCode === 501) {
95
+ return null;
96
+ }
97
+ if (err.statusCode === 403) {
98
+ logger_1.default.debug('Rate Limit Policies feature is not enabled for this tenant. Please contact Auth0 support to enable this feature.');
99
+ return null;
100
+ }
101
+ throw err;
102
+ }
103
+ }
104
+ async processChanges(assets) {
105
+ const { rateLimitPolicies } = assets;
106
+ if (!rateLimitPolicies)
107
+ return;
108
+ const { del, update, create } = await this.calcChanges(assets);
109
+ if ((0, utils_1.isDryRun)(this.config)) {
110
+ if (create.length === 0 && update.length === 0 && del.length === 0) {
111
+ return;
112
+ }
113
+ }
114
+ logger_1.default.debug(`Start processChanges for rateLimitPolicies [delete:${del.length}] [update:${update.length}], [create:${create.length}]`);
115
+ const changes = [{ del }, { create }, { update }];
116
+ await Promise.all(changes.map(async (change) => {
117
+ switch (true) {
118
+ case change.del && change.del.length > 0:
119
+ await this.deleteRateLimitPolicies(change.del);
120
+ break;
121
+ case change.create && change.create.length > 0:
122
+ await this.createRateLimitPolicies(change.create);
123
+ break;
124
+ case change.update && change.update.length > 0:
125
+ await this.updateRateLimitPolicies(change.update);
126
+ break;
127
+ default:
128
+ break;
129
+ }
130
+ }));
131
+ }
132
+ async createRateLimitPolicy(policy) {
133
+ const created = await this.client.rateLimitPolicies.create(policy);
134
+ return created;
135
+ }
136
+ async createRateLimitPolicies(creates) {
137
+ await this.client.pool
138
+ .addEachTask({
139
+ data: creates || [],
140
+ generator: (item) => this.createRateLimitPolicy(item)
141
+ .then((data) => {
142
+ this.didCreate(data);
143
+ this.created += 1;
144
+ })
145
+ .catch((err) => {
146
+ throw new Error(`Problem creating ${this.type} ${this.objString(item)}\n${err}`);
147
+ }),
148
+ })
149
+ .promise();
150
+ }
151
+ async updateRateLimitPolicy(policy) {
152
+ const { id, configuration } = policy;
153
+ if (!id) {
154
+ throw new Error(`Missing id for ${this.type} ${this.objString(policy)}`);
155
+ }
156
+ await this.client.rateLimitPolicies.update(id, { configuration });
157
+ }
158
+ async updateRateLimitPolicies(updates) {
159
+ await this.client.pool
160
+ .addEachTask({
161
+ data: updates || [],
162
+ generator: (item) => this.updateRateLimitPolicy(item)
163
+ .then(() => {
164
+ this.didUpdate(item);
165
+ this.updated += 1;
166
+ })
167
+ .catch((err) => {
168
+ throw new Error(`Problem updating ${this.type} ${this.objString(item)}\n${err}`);
169
+ }),
170
+ })
171
+ .promise();
172
+ }
173
+ async deleteRateLimitPolicy(policy) {
174
+ if (!policy.id) {
175
+ throw new Error(`Missing id for ${this.type} ${this.objString(policy)}`);
176
+ }
177
+ await this.client.rateLimitPolicies.delete(policy.id);
178
+ }
179
+ async deleteRateLimitPolicies(data) {
180
+ if (this.config('AUTH0_ALLOW_DELETE') === 'true' ||
181
+ this.config('AUTH0_ALLOW_DELETE') === true) {
182
+ await this.client.pool
183
+ .addEachTask({
184
+ data: data || [],
185
+ generator: (item) => this.deleteRateLimitPolicy(item)
186
+ .then(() => {
187
+ this.didDelete(item);
188
+ this.deleted += 1;
189
+ })
190
+ .catch((err) => {
191
+ throw new Error(`Problem deleting ${this.type} ${this.objString(item)}\n${err}`);
192
+ }),
193
+ })
194
+ .promise();
195
+ }
196
+ else {
197
+ logger_1.default.warn(`Detected the following ${this.type} should be deleted. Doing so may be destructive.\nYou can enable deletes by setting 'AUTH0_ALLOW_DELETE' to true in the config\n${data
198
+ .map((i) => this.objString(i))
199
+ .join('\n')}`);
200
+ }
201
+ }
202
+ }
203
+ exports.default = RateLimitPoliciesHandler;
@@ -90,6 +90,7 @@ declare const constants: {
90
90
  CONNECTION_PROFILES_DIRECTORY: string;
91
91
  TOKEN_EXCHANGE_PROFILES_DIRECTORY: string;
92
92
  SUPPLEMENTAL_SIGNALS_DIRECTORY: string;
93
+ RATE_LIMIT_POLICIES_DIRECTORY: string;
93
94
  EVENT_STREAMS_DIRECTORY: string;
94
95
  };
95
96
  export default constants;
@@ -220,6 +220,7 @@ const constants = {
220
220
  CONNECTION_PROFILES_DIRECTORY: 'connection-profiles',
221
221
  TOKEN_EXCHANGE_PROFILES_DIRECTORY: 'token-exchange-profiles',
222
222
  SUPPLEMENTAL_SIGNALS_DIRECTORY: 'supplemental-signals',
223
+ RATE_LIMIT_POLICIES_DIRECTORY: 'rate-limit-policies',
223
224
  EVENT_STREAMS_DIRECTORY: 'event-streams',
224
225
  };
225
226
  exports.default = constants;
package/lib/types.d.ts CHANGED
@@ -21,6 +21,7 @@ import { AttackProtection } from './tools/auth0/handlers/attackProtection';
21
21
  import { TokenExchangeProfile } from './tools/auth0/handlers/tokenExchangeProfiles';
22
22
  import { RiskAssessment } from './tools/auth0/handlers/riskAssessment';
23
23
  import { SupplementalSignals } from './tools/auth0/handlers/supplementalSignals';
24
+ import { RateLimitPolicy } from './tools/auth0/handlers/rateLimitPolicies';
24
25
  import { EventStream } from './tools/auth0/handlers/eventStreams';
25
26
  type SharedPaginationParams = {
26
27
  checkpoint?: boolean;
@@ -159,6 +160,7 @@ export type Assets = Partial<{
159
160
  userAttributeProfilesWithId: UserAttributeProfile[] | null;
160
161
  connectionProfiles: Asset[] | null;
161
162
  tokenExchangeProfiles: TokenExchangeProfile[] | null;
163
+ rateLimitPolicies: RateLimitPolicy[] | null;
162
164
  eventStreams: EventStream[] | null;
163
165
  }>;
164
166
  export type CalculatedChanges = {
@@ -180,7 +182,7 @@ export type DetailedDryRunChanges = {
180
182
  changes: DetailedDryRunChange[];
181
183
  };
182
184
  };
183
- export type AssetTypes = 'rules' | 'rulesConfigs' | 'hooks' | 'pages' | 'databases' | 'clientGrants' | 'resourceServers' | 'clients' | 'connections' | 'tenant' | 'emailProvider' | 'emailTemplates' | 'guardianFactors' | 'guardianFactorProviders' | 'guardianFactorTemplates' | 'guardianPhoneFactorMessageTypes' | 'guardianPhoneFactorSelectedProvider' | 'guardianPolicies' | 'roles' | 'actions' | 'actionModules' | 'organizations' | 'triggers' | 'attackProtection' | 'riskAssessment' | 'branding' | 'phoneProviders' | 'phoneTemplates' | 'logStreams' | 'prompts' | 'customDomains' | 'themes' | 'forms' | 'flows' | 'flowVaultConnections' | 'selfServiceProfiles' | 'networkACLs' | 'userAttributeProfiles' | 'connectionProfiles' | 'tokenExchangeProfiles' | 'supplementalSignals' | 'eventStreams';
185
+ export type AssetTypes = 'rules' | 'rulesConfigs' | 'hooks' | 'pages' | 'databases' | 'clientGrants' | 'resourceServers' | 'clients' | 'connections' | 'tenant' | 'emailProvider' | 'emailTemplates' | 'guardianFactors' | 'guardianFactorProviders' | 'guardianFactorTemplates' | 'guardianPhoneFactorMessageTypes' | 'guardianPhoneFactorSelectedProvider' | 'guardianPolicies' | 'roles' | 'actions' | 'actionModules' | 'organizations' | 'triggers' | 'attackProtection' | 'riskAssessment' | 'branding' | 'phoneProviders' | 'phoneTemplates' | 'logStreams' | 'prompts' | 'customDomains' | 'themes' | 'forms' | 'flows' | 'flowVaultConnections' | 'selfServiceProfiles' | 'networkACLs' | 'userAttributeProfiles' | 'connectionProfiles' | 'tokenExchangeProfiles' | 'supplementalSignals' | 'rateLimitPolicies' | 'eventStreams' | 'clientAuthCredentials';
184
186
  export type KeywordMappings = {
185
187
  [key: string]: (string | number)[] | string | number;
186
188
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "auth0-deploy-cli",
3
- "version": "8.39.0",
3
+ "version": "8.41.0",
4
4
  "description": "A command line tool for deploying updates to your Auth0 tenant",
5
5
  "main": "lib/index.js",
6
6
  "bin": {
@@ -35,7 +35,7 @@
35
35
  "dependencies": {
36
36
  "@clack/prompts": "1.4.0",
37
37
  "ajv": "^6.12.6",
38
- "auth0": "^5.13.0",
38
+ "auth0": "^6.0.0",
39
39
  "chalk": "5.6.2",
40
40
  "dot-prop": "^5.3.0",
41
41
  "fs-extra": "^10.1.0",