auth0-deploy-cli 8.26.0 → 8.27.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.
package/CHANGELOG.md CHANGED
@@ -7,6 +7,19 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
7
7
 
8
8
  ## [Unreleased]
9
9
 
10
+ ## [8.27.0] - 2026-02-13
11
+
12
+ ### Added
13
+
14
+ - Add support for `custom_password_hash.action_id` in `databases` (Universal Custom Password Hash EA). [#1288]
15
+ - Add support for `allowed_strategies` in `selfServiceProfiles`. [#1298]
16
+
17
+ ### Fixed
18
+
19
+ - Fix validation handling for `authentication_methods.password.enabled` and `disable_self_service_change_password` in `databases`. [#1297]
20
+ - Fix stripping deprecated `enabled_clients` for `connections` with enhanced client management. [#1294]
21
+ - Fix exclude third-party `clientGrants` when `AUTH0_EXCLUDE_THIRD_PARTY_CLIENTS` is enabled. [#1289]
22
+
10
23
  ## [8.26.0] - 2026-01-30
11
24
 
12
25
  ### Added
@@ -1634,7 +1647,13 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
1634
1647
  [#1282]: https://github.com/auth0/auth0-deploy-cli/issues/1282
1635
1648
  [#1283]: https://github.com/auth0/auth0-deploy-cli/issues/1283
1636
1649
  [#1284]: https://github.com/auth0/auth0-deploy-cli/issues/1284
1637
- [Unreleased]: https://github.com/auth0/auth0-deploy-cli/compare/v8.26.0...HEAD
1650
+ [#1288]: https://github.com/auth0/auth0-deploy-cli/issues/1288
1651
+ [#1289]: https://github.com/auth0/auth0-deploy-cli/issues/1289
1652
+ [#1294]: https://github.com/auth0/auth0-deploy-cli/issues/1294
1653
+ [#1297]: https://github.com/auth0/auth0-deploy-cli/issues/1297
1654
+ [#1298]: https://github.com/auth0/auth0-deploy-cli/issues/1298
1655
+ [Unreleased]: https://github.com/auth0/auth0-deploy-cli/compare/v8.27.0...HEAD
1656
+ [8.27.0]: https://github.com/auth0/auth0-deploy-cli/compare/v8.26.0...v8.27.0
1638
1657
  [8.26.0]: https://github.com/auth0/auth0-deploy-cli/compare/v8.25.0...v8.26.0
1639
1658
  [8.25.0]: https://github.com/auth0/auth0-deploy-cli/compare/v8.24.0...v8.25.0
1640
1659
  [8.24.0]: https://github.com/auth0/auth0-deploy-cli/compare/v8.23.2...v8.24.0
@@ -117,6 +117,15 @@ class ClientGrantsHandler extends default_1.default {
117
117
  // As it could cause problems if the grants are deleted or updated etc
118
118
  const currentClient = this.config('AUTH0_CLIENT_ID');
119
119
  this.existing = this.existing.filter((grant) => grant.client_id !== currentClient);
120
+ // Filter out third-party client grants when AUTH0_EXCLUDE_THIRD_PARTY_CLIENTS is enabled
121
+ if ((0, utils_1.shouldExcludeThirdPartyClients)(this.config)) {
122
+ const clients = await (0, client_1.paginate)(this.client.clients.list, {
123
+ paginate: true,
124
+ is_first_party: true,
125
+ });
126
+ const firstPartyClientIds = new Set(clients.map((c) => c.client_id));
127
+ this.existing = this.existing.filter((grant) => firstPartyClientIds.has(grant.client_id));
128
+ }
120
129
  return this.existing;
121
130
  }
122
131
  // Run after clients are updated so we can convert client_id names to id's
@@ -140,19 +149,28 @@ class ClientGrantsHandler extends default_1.default {
140
149
  });
141
150
  // Always filter out the client we are using to access Auth0 Management API
142
151
  const currentClient = this.config('AUTH0_CLIENT_ID');
152
+ // Build a set of third-party client IDs for efficient lookup
153
+ const thirdPartyClientIds = new Set(clients.filter((c) => c.is_first_party === false).map((c) => c.client_id));
143
154
  const { del, update, create, conflicts } = await this.calcChanges({
144
155
  ...assets,
145
156
  clientGrants: formatted,
146
157
  });
147
158
  const filterGrants = (list) => {
159
+ let filtered = list;
160
+ // Filter out the current client (Auth0 Management API client)
161
+ filtered = filtered.filter((item) => item.client_id !== currentClient);
162
+ // Filter out excluded clients
148
163
  if (excludedClients.length) {
149
- return list.filter((item) => item.client_id !== currentClient &&
150
- item.client_id &&
164
+ filtered = filtered.filter((item) => item.client_id &&
151
165
  ![...excludedClientsByNames, ...excludedClients].includes(item.client_id));
152
166
  }
153
- return list
154
- .filter((item) => item.client_id !== currentClient)
155
- .filter((item) => item.is_system !== true);
167
+ // Filter out system grants
168
+ filtered = filtered.filter((item) => item.is_system !== true);
169
+ // Filter out third-party client grants when flag is enabled
170
+ if ((0, utils_1.shouldExcludeThirdPartyClients)(this.config)) {
171
+ filtered = filtered.filter((item) => !thirdPartyClientIds.has(item.client_id));
172
+ }
173
+ return filtered;
156
174
  };
157
175
  const changes = {
158
176
  // @ts-ignore because this expects `client_id` and that's not yet typed on Asset
@@ -10,6 +10,7 @@ const default_1 = __importDefault(require("./default"));
10
10
  const connectionProfiles_1 = require("./connectionProfiles");
11
11
  const userAttributeProfiles_1 = require("./userAttributeProfiles");
12
12
  const logger_1 = __importDefault(require("../../../logger"));
13
+ const utils_1 = require("../../utils");
13
14
  const multiResourceRefreshTokenPoliciesSchema = {
14
15
  type: ['array', 'null'],
15
16
  description: 'A collection of policies governing multi-resource refresh token exchange (MRRT), defining how refresh tokens can be used across different resource servers',
@@ -397,8 +398,6 @@ class ClientHandler extends default_1.default {
397
398
  return;
398
399
  assets.clients = await this.sanitizeMapExpressConfiguration(this.client, clients);
399
400
  const excludedClients = (assets.exclude && assets.exclude.clients) || [];
400
- const excludeThirdPartyClients = this.config('AUTH0_EXCLUDE_THIRD_PARTY_CLIENTS') === 'true' ||
401
- this.config('AUTH0_EXCLUDE_THIRD_PARTY_CLIENTS') === true;
402
401
  const { del, update, create, conflicts } = await this.calcChanges(assets);
403
402
  // Always filter out the client we are using to access Auth0 Management API
404
403
  // As it could cause problems if it gets deleted or updated etc
@@ -412,7 +411,7 @@ class ClientHandler extends default_1.default {
412
411
  const filterClients = (list) => list.filter((item) => item.client_id !== currentClient &&
413
412
  item.name &&
414
413
  !excludedClients.includes(item.name) &&
415
- (!excludeThirdPartyClients || item.is_first_party));
414
+ (!(0, utils_1.shouldExcludeThirdPartyClients)(this.config) || item.is_first_party));
416
415
  // Sanitize client fields
417
416
  const sanitizeClientFields = (list) => {
418
417
  const sanitizedClients = createClientSanitizer(list)
@@ -447,12 +446,10 @@ class ClientHandler extends default_1.default {
447
446
  async getType() {
448
447
  if (this.existing)
449
448
  return this.existing;
450
- const excludeThirdPartyClients = this.config('AUTH0_EXCLUDE_THIRD_PARTY_CLIENTS') === 'true' ||
451
- this.config('AUTH0_EXCLUDE_THIRD_PARTY_CLIENTS') === true;
452
449
  const clients = await (0, client_1.paginate)(this.client.clients.list, {
453
450
  paginate: true,
454
451
  is_global: false,
455
- ...(excludeThirdPartyClients && { is_first_party: true }),
452
+ ...((0, utils_1.shouldExcludeThirdPartyClients)(this.config) && { is_first_party: true }),
456
453
  });
457
454
  this.existing = createClientSanitizer(clients).sanitizeCrossOriginAuth().get();
458
455
  return this.existing;
@@ -141,7 +141,7 @@ export declare const getConnectionEnabledClients: (auth0Client: Auth0APIClient,
141
141
  * @returns Promise that resolves to true if the update was successful, false otherwise
142
142
  *
143
143
  */
144
- export declare const updateConnectionEnabledClients: (auth0Client: Auth0APIClient, typeName: string, connectionId: string, enabledClientIds: string[]) => Promise<boolean>;
144
+ export declare const updateConnectionEnabledClients: (auth0Client: Auth0APIClient, typeName: string, connectionId: string, enabledClientIds: string[], existingConnections: Asset[] | Asset | null) => Promise<boolean>;
145
145
  /**
146
146
  * This function processes enabled clients for create, update, and conflict operations.
147
147
  * Note: This function mutates the `create` array by adding IDs to the connection objects after creation.
@@ -153,7 +153,7 @@ export declare const updateConnectionEnabledClients: (auth0Client: Auth0APIClien
153
153
  *
154
154
  * @returns A Promise that resolves when all enabled client updates are complete
155
155
  */
156
- export declare const processConnectionEnabledClients: (auth0Client: Auth0APIClient, typeName: string, changes: CalculatedChanges, delayMs?: number) => Promise<void>;
156
+ export declare const processConnectionEnabledClients: (auth0Client: Auth0APIClient, typeName: string, existingConnections: Asset[] | null, changes: CalculatedChanges, delayMs?: number) => Promise<void>;
157
157
  export default class ConnectionsHandler extends DefaultAPIHandler {
158
158
  existing: Connection[] | null;
159
159
  scimHandler: ScimHandler;
@@ -200,13 +200,36 @@ exports.getConnectionEnabledClients = getConnectionEnabledClients;
200
200
  * @returns Promise that resolves to true if the update was successful, false otherwise
201
201
  *
202
202
  */
203
- const updateConnectionEnabledClients = async (auth0Client, typeName, connectionId, enabledClientIds) => {
203
+ const updateConnectionEnabledClients = async (auth0Client, typeName, connectionId, enabledClientIds, existingConnections) => {
204
204
  if (!connectionId || !Array.isArray(enabledClientIds) || !enabledClientIds.length)
205
205
  return false;
206
- const enabledClientUpdatePayloads = enabledClientIds.map((clientId) => ({
207
- client_id: clientId,
208
- status: true,
209
- }));
206
+ let existingEnabledClients = [];
207
+ if (Array.isArray(existingConnections)) {
208
+ const existingConnection = existingConnections.find((con) => con.id === connectionId);
209
+ existingEnabledClients = existingConnection?.enabled_clients ?? [];
210
+ }
211
+ // Determine which clients to enable vs. disable by comparing the incoming `enabledClientIds` with the `existingEnabledClients`.
212
+ const enabledClientIdSet = new Set(enabledClientIds);
213
+ const existingClientIdSet = new Set(existingEnabledClients);
214
+ // If both sets are identical, skip the update entirely.
215
+ if (enabledClientIdSet.size === existingClientIdSet.size &&
216
+ [...enabledClientIdSet].every((id) => existingClientIdSet.has(id))) {
217
+ logger_1.default.debug(`Enabled clients for ${typeName}: ${connectionId} are unchanged, skipping update`);
218
+ return true;
219
+ }
220
+ const clientsToEnable = enabledClientIds;
221
+ // Any client that exists on the tenant but not in the provided `enabledClientIds` should be disabled.
222
+ const clientsToDisable = existingEnabledClients.filter((clientId) => !enabledClientIdSet.has(clientId));
223
+ const enabledClientUpdatePayloads = [
224
+ ...clientsToEnable.map((clientId) => ({
225
+ client_id: clientId,
226
+ status: true,
227
+ })),
228
+ ...clientsToDisable.map((clientId) => ({
229
+ client_id: clientId,
230
+ status: false,
231
+ })),
232
+ ];
210
233
  const payloadChunks = (0, lodash_1.chunk)(enabledClientUpdatePayloads, 50);
211
234
  try {
212
235
  await Promise.all(payloadChunks.map((payload) => auth0Client.connections.clients.update(connectionId, payload)));
@@ -230,7 +253,7 @@ exports.updateConnectionEnabledClients = updateConnectionEnabledClients;
230
253
  *
231
254
  * @returns A Promise that resolves when all enabled client updates are complete
232
255
  */
233
- const processConnectionEnabledClients = async (auth0Client, typeName, changes, delayMs = 2500 // Default delay is 2.5 seconds
256
+ const processConnectionEnabledClients = async (auth0Client, typeName, existingConnections, changes, delayMs = 2500 // Default delay is 2.5 seconds
234
257
  ) => {
235
258
  const { create, update, conflicts } = changes;
236
259
  let createWithId = [];
@@ -267,9 +290,9 @@ const processConnectionEnabledClients = async (auth0Client, typeName, changes, d
267
290
  // Process enabled clients for each change type
268
291
  // Delete is handled by the `processChanges` method, removed connection completely
269
292
  await Promise.all([
270
- ...createWithId.map((conn) => (0, exports.updateConnectionEnabledClients)(auth0Client, typeName, conn.id, conn.enabled_clients)),
271
- ...update.map((conn) => (0, exports.updateConnectionEnabledClients)(auth0Client, typeName, conn.id, conn.enabled_clients)),
272
- ...conflicts.map((conn) => (0, exports.updateConnectionEnabledClients)(auth0Client, typeName, conn.id, conn.enabled_clients)),
293
+ ...createWithId.map((conn) => (0, exports.updateConnectionEnabledClients)(auth0Client, typeName, conn.id, conn.enabled_clients, existingConnections)),
294
+ ...update.map((conn) => (0, exports.updateConnectionEnabledClients)(auth0Client, typeName, conn.id, conn.enabled_clients, existingConnections)),
295
+ ...conflicts.map((conn) => (0, exports.updateConnectionEnabledClients)(auth0Client, typeName, conn.id, conn.enabled_clients, existingConnections)),
273
296
  ]);
274
297
  };
275
298
  exports.processConnectionEnabledClients = processConnectionEnabledClients;
@@ -543,7 +566,7 @@ class ConnectionsHandler extends default_1.default {
543
566
  changes = (0, utils_1.filterIncluded)(changes, includedConnections);
544
567
  await super.processChanges(assets, changes);
545
568
  // process enabled clients
546
- await (0, exports.processConnectionEnabledClients)(this.client, this.type, changes);
569
+ await (0, exports.processConnectionEnabledClients)(this.client, this.type, await this.existing, changes);
547
570
  // process directory provisioning
548
571
  await this.processConnectionDirectoryProvisioning(changes);
549
572
  }
@@ -1,5 +1,7 @@
1
1
  import DefaultAPIHandler from './default';
2
- import { CalculatedChanges, Assets, Asset } from '../../../types';
2
+ import { CalculatedChanges, Assets } from '../../../types';
3
+ import { Connection } from './connections';
4
+ import { Action } from './actions';
3
5
  export declare const schema: {
4
6
  type: string;
5
7
  items: {
@@ -180,6 +182,14 @@ export declare const schema: {
180
182
  };
181
183
  };
182
184
  };
185
+ custom_password_hash: {
186
+ type: string;
187
+ properties: {
188
+ action_id: {
189
+ type: string;
190
+ };
191
+ };
192
+ };
183
193
  };
184
194
  };
185
195
  };
@@ -187,13 +197,15 @@ export declare const schema: {
187
197
  };
188
198
  };
189
199
  export default class DatabaseHandler extends DefaultAPIHandler {
200
+ existing: Connection[] | null;
190
201
  constructor(config: DefaultAPIHandler);
191
202
  objString(db: any): string;
203
+ getFormattedOptions(options: any, actions?: Action[]): any;
192
204
  validate(assets: Assets): Promise<void>;
193
205
  private validatePasswordlessSettings;
194
206
  private validateEmailUniqueConstraints;
195
207
  getClientFN(fn: 'create' | 'delete' | 'getAll' | 'update'): Function;
196
- getType(): Promise<Asset | Asset[]>;
208
+ getType(): Promise<Connection[]>;
197
209
  calcChanges(assets: Assets): Promise<CalculatedChanges>;
198
210
  processChanges(assets: Assets): Promise<void>;
199
211
  }
@@ -173,6 +173,12 @@ exports.schema = {
173
173
  },
174
174
  },
175
175
  },
176
+ custom_password_hash: {
177
+ type: 'object',
178
+ properties: {
179
+ action_id: { type: 'string' },
180
+ },
181
+ },
176
182
  },
177
183
  },
178
184
  },
@@ -190,6 +196,22 @@ class DatabaseHandler extends default_1.default {
190
196
  objString(db) {
191
197
  return super.objString({ name: db.name, id: db.id });
192
198
  }
199
+ getFormattedOptions(options, actions = []) {
200
+ try {
201
+ const formattedOptions = { ...options };
202
+ // Handle custom_password_hash.action_id conversion
203
+ if (options?.custom_password_hash?.action_id) {
204
+ formattedOptions.custom_password_hash = {
205
+ ...options.custom_password_hash,
206
+ action_id: (0, utils_1.convertActionNameToId)(options.custom_password_hash.action_id, actions),
207
+ };
208
+ }
209
+ return formattedOptions;
210
+ }
211
+ catch (e) {
212
+ return {};
213
+ }
214
+ }
193
215
  async validate(assets) {
194
216
  const { databases } = assets;
195
217
  // Do nothing if not set
@@ -198,7 +220,7 @@ class DatabaseHandler extends default_1.default {
198
220
  // Validate each database
199
221
  databases.forEach((database) => {
200
222
  this.validateEmailUniqueConstraints(database);
201
- this.validatePasswordlessSettings(database);
223
+ // this.validatePasswordlessSettings(database); // Enable only the feature is GA PR:#1282
202
224
  });
203
225
  await super.validate(assets);
204
226
  }
@@ -242,7 +264,12 @@ class DatabaseHandler extends default_1.default {
242
264
  getClientFN(fn) {
243
265
  // Override this as a database is actually a connection but we are treating them as a different object
244
266
  if (fn === 'create') {
245
- return (payload) => this.client.connections.create(payload);
267
+ return (payload) => {
268
+ // Remove deprecated enabled_clients field
269
+ if ('enabled_clients' in payload)
270
+ delete payload.enabled_clients;
271
+ return this.client.connections.create(payload);
272
+ };
246
273
  }
247
274
  // If we going to update database, we need to get current options first
248
275
  if (fn === 'update') {
@@ -265,6 +292,9 @@ class DatabaseHandler extends default_1.default {
265
292
  if (payload.options && Object.keys(payload.options).length === 0) {
266
293
  delete payload.options;
267
294
  }
295
+ // Remove deprecated enabled_clients field
296
+ if ('enabled_clients' in payload)
297
+ delete payload.enabled_clients;
268
298
  return this.client.connections.update(id, payload);
269
299
  });
270
300
  }
@@ -273,25 +303,52 @@ class DatabaseHandler extends default_1.default {
273
303
  async getType() {
274
304
  if (this.existing)
275
305
  return this.existing;
276
- const connections = await (0, client_1.paginate)(this.client.connections.list, {
277
- strategy: [auth0_1.Management.ConnectionStrategyEnum.Auth0],
278
- checkpoint: true,
279
- });
306
+ // Fetch connections and actions concurrently
307
+ const [connections, actions] = await Promise.all([
308
+ (0, client_1.paginate)(this.client.connections.list, {
309
+ strategy: [auth0_1.Management.ConnectionStrategyEnum.Auth0],
310
+ checkpoint: true,
311
+ }),
312
+ (0, client_1.paginate)(this.client.actions.list, {
313
+ paginate: true,
314
+ include_totals: true,
315
+ }),
316
+ ]);
280
317
  const dbConnectionsWithEnabledClients = await Promise.all(connections.map(async (con) => {
281
318
  if (!con?.id)
282
319
  return con;
283
320
  const enabledClients = await (0, connections_1.getConnectionEnabledClients)(this.client, con.id);
321
+ const connection = { ...con };
284
322
  if (enabledClients && enabledClients?.length) {
285
- return { ...con, enabled_clients: enabledClients };
323
+ connection.enabled_clients = enabledClients;
286
324
  }
287
- return con;
325
+ return connection;
288
326
  }));
327
+ // Convert action ID back to action name for export
328
+ const dbConnectionsWithActionNames = dbConnectionsWithEnabledClients.map((connection) => {
329
+ if (connection.options && 'custom_password_hash' in connection.options) {
330
+ const customPasswordHash = connection.options?.custom_password_hash;
331
+ if (customPasswordHash?.action_id) {
332
+ return {
333
+ ...connection,
334
+ options: {
335
+ ...connection.options,
336
+ custom_password_hash: {
337
+ ...customPasswordHash,
338
+ action_id: (0, utils_1.convertActionIdToName)(customPasswordHash.action_id, actions),
339
+ },
340
+ },
341
+ };
342
+ }
343
+ }
344
+ return connection;
345
+ });
289
346
  // If options option is empty for all connection, log the missing options scope.
290
- const isOptionExists = dbConnectionsWithEnabledClients.every((c) => c.options && Object.keys(c.options).length > 0);
347
+ const isOptionExists = dbConnectionsWithActionNames.every((c) => c.options && Object.keys(c.options).length > 0);
291
348
  if (!isOptionExists) {
292
349
  logger_1.default.warn(`Insufficient scope the read:connections_options scope is required to get ${this.type} options.`);
293
350
  }
294
- this.existing = dbConnectionsWithEnabledClients;
351
+ this.existing = dbConnectionsWithActionNames;
295
352
  return this.existing;
296
353
  }
297
354
  async calcChanges(assets) {
@@ -305,22 +362,29 @@ class DatabaseHandler extends default_1.default {
305
362
  conflicts: [],
306
363
  };
307
364
  // Convert enabled_clients by name to the id
308
- const clients = await (0, client_1.paginate)(this.client.clients.list, {
309
- paginate: true,
310
- });
311
- const existingDatabasesConnections = await (0, client_1.paginate)(this.client.connections.list, {
312
- strategy: [auth0_1.Management.ConnectionStrategyEnum.Auth0],
313
- checkpoint: true,
314
- include_totals: true,
315
- });
365
+ // Fetch clients, connections, and actions concurrently
366
+ const [clients, existingDatabasesConnections, actions] = await Promise.all([
367
+ (0, client_1.paginate)(this.client.clients.list, {
368
+ paginate: true,
369
+ }),
370
+ (0, client_1.paginate)(this.client.connections.list, {
371
+ strategy: [auth0_1.Management.ConnectionStrategyEnum.Auth0],
372
+ checkpoint: true,
373
+ include_totals: true,
374
+ }),
375
+ (0, client_1.paginate)(this.client.actions.list, {
376
+ paginate: true,
377
+ include_totals: true,
378
+ }),
379
+ ]);
316
380
  const formatted = databases.map((db) => {
381
+ const { options, ...rest } = db;
382
+ const formattedOptions = this.getFormattedOptions(options, actions);
383
+ const formattedDb = { ...rest, options: formattedOptions };
317
384
  if (db.enabled_clients) {
318
- return {
319
- ...db,
320
- enabled_clients: (0, utils_1.getEnabledClients)(assets, db, existingDatabasesConnections, clients),
321
- };
385
+ formattedDb.enabled_clients = (0, utils_1.getEnabledClients)(assets, db, existingDatabasesConnections, clients);
322
386
  }
323
- return db;
387
+ return formattedDb;
324
388
  });
325
389
  return super.calcChanges({ ...assets, databases: formatted });
326
390
  }
@@ -339,7 +403,7 @@ class DatabaseHandler extends default_1.default {
339
403
  const changes = await this.calcChanges(assets);
340
404
  await super.processChanges(assets, (0, utils_1.filterExcluded)(changes, excludedConnections));
341
405
  // process enabled clients
342
- await (0, connections_1.processConnectionEnabledClients)(this.client, this.type, (0, utils_1.filterExcluded)(changes, excludedConnections));
406
+ await (0, connections_1.processConnectionEnabledClients)(this.client, this.type, await this.existing, (0, utils_1.filterExcluded)(changes, excludedConnections));
343
407
  }
344
408
  }
345
409
  exports.default = DatabaseHandler;
@@ -191,6 +191,9 @@ class ScimHandler {
191
191
  const { scim_configuration: scimBodyParams } = bodyParams;
192
192
  delete bodyParams.scim_configuration;
193
193
  delete bodyParams.directory_provisioning_configuration;
194
+ // Remove deprecated enabled_clients field
195
+ if ('enabled_clients' in bodyParams)
196
+ delete bodyParams.enabled_clients;
194
197
  // First, update `connections`.
195
198
  const updated = await this.connectionsManager.update(connectionId, bodyParams);
196
199
  const idMapEntry = this.idMap.get(connectionId);
@@ -225,6 +228,9 @@ class ScimHandler {
225
228
  const { scim_configuration: scimBodyParams } = bodyParams;
226
229
  delete bodyParams.scim_configuration;
227
230
  delete bodyParams.directory_provisioning_configuration;
231
+ // Remove deprecated enabled_clients field
232
+ if ('enabled_clients' in bodyParams)
233
+ delete bodyParams.enabled_clients;
228
234
  // First, create the new `connection`.
229
235
  const data = await this.connectionsManager.create(bodyParams);
230
236
  if (data?.id && scimBodyParams && this.scimScopes.create) {
@@ -48,6 +48,14 @@ export declare const schema: {
48
48
  };
49
49
  };
50
50
  };
51
+ allowed_strategies: {
52
+ type: string;
53
+ description: string;
54
+ items: {
55
+ type: string;
56
+ enum: ("pingfederate" | "adfs" | "waad" | "google-apps" | "okta" | "oidc" | "samlp" | "auth0-samlp" | "okta-samlp" | "keycloak-samlp")[];
57
+ };
58
+ };
51
59
  branding: {
52
60
  type: string;
53
61
  properties: {
@@ -43,6 +43,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
43
43
  };
44
44
  Object.defineProperty(exports, "__esModule", { value: true });
45
45
  exports.schema = void 0;
46
+ const auth0_1 = require("auth0");
46
47
  const lodash_1 = require("lodash");
47
48
  const logger_1 = __importDefault(require("../../../logger"));
48
49
  const default_1 = __importStar(require("./default"));
@@ -86,6 +87,14 @@ exports.schema = {
86
87
  },
87
88
  },
88
89
  },
90
+ allowed_strategies: {
91
+ type: 'array',
92
+ description: 'List of IdP strategies that will be shown to users during the Self-Service SSO flow.',
93
+ items: {
94
+ type: 'string',
95
+ enum: Object.values(auth0_1.Management.SelfServiceProfileAllowedStrategyEnum),
96
+ },
97
+ },
89
98
  branding: {
90
99
  type: 'object',
91
100
  properties: {
@@ -6,6 +6,8 @@ export declare function keywordStringReplace(input: string, mappings: KeywordMap
6
6
  export declare function keywordReplace(input: string | undefined, mappings: KeywordMappings): string;
7
7
  export declare function wrapArrayReplaceMarkersInQuotes(body: string, mappings: KeywordMappings): string;
8
8
  export declare function convertClientNameToId(name: string, clients: Asset[]): string;
9
+ export declare function convertActionNameToId(name: string, actions: Asset[]): string;
10
+ export declare function convertActionIdToName(id: string, actions: Asset[]): string;
9
11
  export declare function convertClientNamesToIds(names: string[], clients: Asset[]): string[];
10
12
  export declare function loadFileAndReplaceKeywords(file: string, { mappings, disableKeywordReplacement, }: {
11
13
  mappings: KeywordMappings;
@@ -44,3 +46,12 @@ export declare function maskSecretAtPath({ resourceTypeName, maskedKeyName, mask
44
46
  maskOnObj: object;
45
47
  keyJsonPath: string;
46
48
  }): any;
49
+ /**
50
+ * Determines whether third-party clients should be excluded based on configuration.
51
+ * Checks the AUTH0_EXCLUDE_THIRD_PARTY_CLIENTS config value and returns true if it's
52
+ * set to boolean true or string 'true'.
53
+ *
54
+ * @param configFn - The configuration function to retrieve the config value.
55
+ * @returns True if third-party clients should be excluded, false otherwise.
56
+ */
57
+ export declare const shouldExcludeThirdPartyClients: (configFn: (key: string) => any) => boolean;
@@ -36,12 +36,14 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
36
36
  return (mod && mod.__esModule) ? mod : { "default": mod };
37
37
  };
38
38
  Object.defineProperty(exports, "__esModule", { value: true });
39
- exports.isForbiddenFeatureError = exports.isDeprecatedError = exports.detectInsufficientScopeError = exports.stripObfuscatedFieldsFromPayload = exports.obfuscateSensitiveValues = exports.keywordReplaceStringRegExp = exports.keywordReplaceArrayRegExp = void 0;
39
+ exports.shouldExcludeThirdPartyClients = exports.isForbiddenFeatureError = exports.isDeprecatedError = exports.detectInsufficientScopeError = exports.stripObfuscatedFieldsFromPayload = exports.obfuscateSensitiveValues = exports.keywordReplaceStringRegExp = exports.keywordReplaceArrayRegExp = void 0;
40
40
  exports.keywordArrayReplace = keywordArrayReplace;
41
41
  exports.keywordStringReplace = keywordStringReplace;
42
42
  exports.keywordReplace = keywordReplace;
43
43
  exports.wrapArrayReplaceMarkersInQuotes = wrapArrayReplaceMarkersInQuotes;
44
44
  exports.convertClientNameToId = convertClientNameToId;
45
+ exports.convertActionNameToId = convertActionNameToId;
46
+ exports.convertActionIdToName = convertActionIdToName;
45
47
  exports.convertClientNamesToIds = convertClientNamesToIds;
46
48
  exports.loadFileAndReplaceKeywords = loadFileAndReplaceKeywords;
47
49
  exports.flatten = flatten;
@@ -115,6 +117,14 @@ function convertClientNameToId(name, clients) {
115
117
  const found = clients.find((c) => c.name === name);
116
118
  return (found && found.client_id) || name;
117
119
  }
120
+ function convertActionNameToId(name, actions) {
121
+ const found = actions.find((a) => a.name === name);
122
+ return (found && found.id) || name;
123
+ }
124
+ function convertActionIdToName(id, actions) {
125
+ const found = actions.find((a) => a.id === id);
126
+ return (found && found.name) || id;
127
+ }
118
128
  function convertClientNamesToIds(names, clients) {
119
129
  const resolvedNames = names.map((name) => ({ name, resolved: false }));
120
130
  const result = clients.reduce((acc, client) => {
@@ -311,3 +321,16 @@ function maskSecretAtPath({ resourceTypeName, maskedKeyName, maskOnObj, keyJsonP
311
321
  }
312
322
  return maskOnObj;
313
323
  }
324
+ /**
325
+ * Determines whether third-party clients should be excluded based on configuration.
326
+ * Checks the AUTH0_EXCLUDE_THIRD_PARTY_CLIENTS config value and returns true if it's
327
+ * set to boolean true or string 'true'.
328
+ *
329
+ * @param configFn - The configuration function to retrieve the config value.
330
+ * @returns True if third-party clients should be excluded, false otherwise.
331
+ */
332
+ const shouldExcludeThirdPartyClients = (configFn) => {
333
+ const value = configFn('AUTH0_EXCLUDE_THIRD_PARTY_CLIENTS');
334
+ return value === 'true' || value === true;
335
+ };
336
+ exports.shouldExcludeThirdPartyClients = shouldExcludeThirdPartyClients;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "auth0-deploy-cli",
3
- "version": "8.26.0",
3
+ "version": "8.27.0",
4
4
  "description": "A command line tool for deploying updates to your Auth0 tenant",
5
5
  "main": "lib/index.js",
6
6
  "bin": {
@@ -33,7 +33,7 @@
33
33
  "homepage": "https://github.com/auth0/auth0-deploy-cli#readme",
34
34
  "dependencies": {
35
35
  "ajv": "^6.12.6",
36
- "auth0": "^5.3.0",
36
+ "auth0": "^5.3.1",
37
37
  "dot-prop": "^5.3.0",
38
38
  "fs-extra": "^10.1.0",
39
39
  "js-yaml": "^4.1.1",
@@ -42,7 +42,7 @@
42
42
  "nconf": "^0.13.0",
43
43
  "promise-pool-executor": "^1.1.1",
44
44
  "sanitize-filename": "^1.6.3",
45
- "undici": "^7.19.2",
45
+ "undici": "^7.21.0",
46
46
  "winston": "^3.19.0",
47
47
  "yargs": "^15.4.1"
48
48
  },
@@ -52,8 +52,8 @@
52
52
  "@types/mocha": "^10.0.10",
53
53
  "@types/nconf": "^0.10.7",
54
54
  "@eslint/js": "^9.39.2",
55
- "@typescript-eslint/eslint-plugin": "^8.54.0",
56
- "@typescript-eslint/parser": "^8.54.0",
55
+ "@typescript-eslint/eslint-plugin": "^8.55.0",
56
+ "@typescript-eslint/parser": "^8.55.0",
57
57
  "chai": "^4.5.0",
58
58
  "chai-as-promised": "^7.1.2",
59
59
  "eslint": "^9.39.2",