Skip to content

Commit d46b544

Browse files
feat(ui,clerk-js,shared,localizations): Add all members of a role to the SSO allow list (#9826)
1 parent 571217d commit d46b544

66 files changed

Lines changed: 1804 additions & 448 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
---
2+
'@clerk/localizations': minor
3+
'@clerk/clerk-js': minor
4+
'@clerk/shared': minor
5+
'@clerk/ui': minor
6+
---
7+
8+
The "Add members" card on the SSO allow list page of `<OrganizationProfile />` now offers two ways to add people: by email address, or every member with a given role at once. Members whose email address is not served by one of the organization's enterprise connections are skipped. When nothing could be added the card stays open and says why, and when some were added it moves to a success step that reports how many were skipped.
9+
10+
For custom flows, `organization.ssoBypassAllowlist` gains `addUsers({ userIds })`, which calls the new bulk endpoint in batches of 100 and returns the added entries together with the users that could not be added and why.
11+
12+
Inputs marked to be ignored by password managers now also carry the Bitwarden, LastPass and Dashlane opt-out attributes, so those extensions stop offering to fill fields such as the allow list email address.
13+
14+
The member picker that the "Add member" card shipped with in 4.18.0 is gone, and so are its localization keys under `organizationProfile.securityPage.ssoBypassPage.addForm`: `memberLabel`, `memberPlaceholder`, `changeButton` and `noResults`. The feature was never enabled on any instance, so no application depends on them.
15+
16+
New customization handles: the `organizationProfileSecuritySsoBypassEmailInput`, `organizationProfileSecuritySsoBypassRoleWarning`, `organizationProfileSecuritySsoBypassFailure` and `organizationProfileSecuritySsoBypassBulkResult` appearance elements.

‎packages/clerk-js/bundlewatch.config.json‎

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,8 @@
22
"files": [
33
{ "path": "./dist/clerk.js", "maxSize": "554KB" },
44
{ "path": "./dist/clerk.browser.js", "maxSize": "81KB" },
5-
{ "path": "./dist/clerk.legacy.browser.js", "maxSize": "122.5KB" },
6-
{ "path": "./dist/clerk.no-rhc.js", "maxSize": "320KB" },
5+
{ "path": "./dist/clerk.legacy.browser.js", "maxSize": "124KB" },
6+
{ "path": "./dist/clerk.no-rhc.js", "maxSize": "322KB" },
77
{ "path": "./dist/clerk.native.js", "maxSize": "80KB" },
88
{ "path": "./dist/vendors*.js", "maxSize": "7KB" },
99
{ "path": "./dist/coinbase*.js", "maxSize": "36KB" },

‎packages/clerk-js/src/core/resources/SSOBypassAllowlist.ts‎

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,10 @@
11
import type {
22
AddSSOBypassAllowlistUserParams,
3+
AddSSOBypassAllowlistUsersParams,
34
DeletedObjectJSON,
45
DeletedObjectResource,
6+
SSOBypassAllowlistBulkCreateJSON,
7+
SSOBypassAllowlistBulkCreateResult,
58
SSOBypassAllowlistResource,
69
SSOBypassAllowlistUserJSON,
710
SSOBypassAllowlistUserResource,
@@ -11,6 +14,8 @@ import { BaseResource } from './Base';
1114
import { DeletedObject } from './DeletedObject';
1215
import { SSOBypassAllowlistUser } from './SSOBypassAllowlistUser';
1316

17+
const BULK_SIZE = 100;
18+
1419
export class SSOBypassAllowlist implements SSOBypassAllowlistResource {
1520
declare private readonly organization: { id: string };
1621

@@ -45,6 +50,25 @@ export class SSOBypassAllowlist implements SSOBypassAllowlistResource {
4550
return new SSOBypassAllowlistUser(json);
4651
};
4752

53+
addUsers = async (params: AddSSOBypassAllowlistUsersParams): Promise<SSOBypassAllowlistBulkCreateResult> => {
54+
const result: SSOBypassAllowlistBulkCreateResult = { data: [], errors: [] };
55+
56+
for (let start = 0; start < params.userIds.length; start += BULK_SIZE) {
57+
const json = (
58+
await BaseResource._fetch({
59+
path: `${this.path}/bulk`,
60+
method: 'POST',
61+
body: { user_id: params.userIds.slice(start, start + BULK_SIZE) } as any,
62+
})
63+
)?.response as unknown as SSOBypassAllowlistBulkCreateJSON;
64+
65+
result.data.push(...(json?.data ?? []).map(entry => new SSOBypassAllowlistUser(entry)));
66+
result.errors.push(...(json?.errors ?? []).map(error => ({ userId: error.user_id, code: error.code })));
67+
}
68+
69+
return result;
70+
};
71+
4872
removeUser = async (userId: string): Promise<DeletedObjectResource> => {
4973
const json = (
5074
await BaseResource._fetch<DeletedObjectJSON>({

‎packages/clerk-js/src/core/resources/__tests__/Organization.test.ts‎

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -468,6 +468,49 @@ describe('Organization', () => {
468468
expect(entry.userId).toBe('user_1');
469469
});
470470

471+
it('adds users in chunks of 100 and merges the partial results', async () => {
472+
const userIds = Array.from({ length: 150 }, (_, i) => `user_${i}`);
473+
const fetchMock = vi
474+
.fn()
475+
.mockResolvedValueOnce({
476+
response: { data: [entryJSON], errors: [{ user_id: 'user_5', code: 'sso_bypass_domain_not_served' }] },
477+
})
478+
.mockResolvedValueOnce({
479+
response: { data: [{ ...entryJSON, user_id: 'user_120' }], errors: [] },
480+
});
481+
// @ts-ignore
482+
BaseResource._fetch = fetchMock;
483+
484+
const organization = createOrganization();
485+
const result = await organization.ssoBypassAllowlist.addUsers({ userIds });
486+
487+
expect(fetchMock).toHaveBeenCalledTimes(2);
488+
expect(fetchMock).toHaveBeenNthCalledWith(1, {
489+
method: 'POST',
490+
path: `${ALLOWLIST_PATH}/bulk`,
491+
body: { user_id: userIds.slice(0, 100) },
492+
});
493+
expect(fetchMock).toHaveBeenNthCalledWith(2, {
494+
method: 'POST',
495+
path: `${ALLOWLIST_PATH}/bulk`,
496+
body: { user_id: userIds.slice(100) },
497+
});
498+
expect(result.data.map(entry => entry.userId)).toEqual(['user_1', 'user_120']);
499+
expect(result.errors).toEqual([{ userId: 'user_5', code: 'sso_bypass_domain_not_served' }]);
500+
});
501+
502+
it('sends nothing for an empty batch', async () => {
503+
// @ts-ignore
504+
BaseResource._fetch = vi.fn();
505+
506+
const organization = createOrganization();
507+
const result = await organization.ssoBypassAllowlist.addUsers({ userIds: [] });
508+
509+
// @ts-ignore
510+
expect(BaseResource._fetch).not.toHaveBeenCalled();
511+
expect(result).toEqual({ data: [], errors: [] });
512+
});
513+
471514
it('removes a user by id', async () => {
472515
// @ts-ignore
473516
BaseResource._fetch = vi

‎packages/localizations/src/ar-SA.ts‎

Lines changed: 21 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1379,14 +1379,30 @@ export const arSA: LocalizationResource = {
13791379
action__add: undefined,
13801380
action__search: undefined,
13811381
addForm: {
1382-
changeButton: undefined,
1383-
memberLabel: undefined,
1384-
memberPlaceholder: undefined,
1385-
noResults: undefined,
1382+
emailPlaceholder: undefined,
1383+
error__allAlreadyAdded: undefined,
1384+
error__alreadyAdded: undefined,
1385+
error__memberNotFound: undefined,
1386+
modeLabel: undefined,
1387+
mode__email: undefined,
1388+
mode__role: undefined,
1389+
roleOption: undefined,
1390+
roleWarning: undefined,
13861391
submitButton: undefined,
13871392
subtitle: undefined,
13881393
title: undefined,
13891394
},
1395+
bulkResult: {
1396+
added: undefined,
1397+
addedMember: undefined,
1398+
added__one: undefined,
1399+
domainNotServed: undefined,
1400+
domainNotServed__one: undefined,
1401+
notMember: undefined,
1402+
notMember__one: undefined,
1403+
unknown: undefined,
1404+
unknown__one: undefined,
1405+
},
13901406
table: {
13911407
emptyState: undefined,
13921408
emptyState__search: undefined,
@@ -2049,6 +2065,7 @@ export const arSA: LocalizationResource = {
20492065
protect_check_timed_out: undefined,
20502066
protect_check_unsupported_environment: undefined,
20512067
session_exists: 'لقد قمت بتسجيل الدخول بالفعل',
2068+
sso_bypass_domain_not_served: undefined,
20522069
ticket_expired_code: undefined,
20532070
ticket_invalid_code: undefined,
20542071
web3_missing_identifier: undefined,

‎packages/localizations/src/be-BY.ts‎

Lines changed: 21 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1382,14 +1382,30 @@ export const beBY: LocalizationResource = {
13821382
action__add: undefined,
13831383
action__search: undefined,
13841384
addForm: {
1385-
changeButton: undefined,
1386-
memberLabel: undefined,
1387-
memberPlaceholder: undefined,
1388-
noResults: undefined,
1385+
emailPlaceholder: undefined,
1386+
error__allAlreadyAdded: undefined,
1387+
error__alreadyAdded: undefined,
1388+
error__memberNotFound: undefined,
1389+
modeLabel: undefined,
1390+
mode__email: undefined,
1391+
mode__role: undefined,
1392+
roleOption: undefined,
1393+
roleWarning: undefined,
13891394
submitButton: undefined,
13901395
subtitle: undefined,
13911396
title: undefined,
13921397
},
1398+
bulkResult: {
1399+
added: undefined,
1400+
addedMember: undefined,
1401+
added__one: undefined,
1402+
domainNotServed: undefined,
1403+
domainNotServed__one: undefined,
1404+
notMember: undefined,
1405+
notMember__one: undefined,
1406+
unknown: undefined,
1407+
unknown__one: undefined,
1408+
},
13931409
table: {
13941410
emptyState: undefined,
13951411
emptyState__search: undefined,
@@ -2060,6 +2076,7 @@ export const beBY: LocalizationResource = {
20602076
protect_check_timed_out: undefined,
20612077
protect_check_unsupported_environment: undefined,
20622078
session_exists: 'Вы ўжо ўвайшлі.',
2079+
sso_bypass_domain_not_served: undefined,
20632080
ticket_expired_code: undefined,
20642081
ticket_invalid_code: undefined,
20652082
web3_missing_identifier: undefined,

‎packages/localizations/src/bg-BG.ts‎

Lines changed: 21 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1382,14 +1382,30 @@ export const bgBG: LocalizationResource = {
13821382
action__add: undefined,
13831383
action__search: undefined,
13841384
addForm: {
1385-
changeButton: undefined,
1386-
memberLabel: undefined,
1387-
memberPlaceholder: undefined,
1388-
noResults: undefined,
1385+
emailPlaceholder: undefined,
1386+
error__allAlreadyAdded: undefined,
1387+
error__alreadyAdded: undefined,
1388+
error__memberNotFound: undefined,
1389+
modeLabel: undefined,
1390+
mode__email: undefined,
1391+
mode__role: undefined,
1392+
roleOption: undefined,
1393+
roleWarning: undefined,
13891394
submitButton: undefined,
13901395
subtitle: undefined,
13911396
title: undefined,
13921397
},
1398+
bulkResult: {
1399+
added: undefined,
1400+
addedMember: undefined,
1401+
added__one: undefined,
1402+
domainNotServed: undefined,
1403+
domainNotServed__one: undefined,
1404+
notMember: undefined,
1405+
notMember__one: undefined,
1406+
unknown: undefined,
1407+
unknown__one: undefined,
1408+
},
13931409
table: {
13941410
emptyState: undefined,
13951411
emptyState__search: undefined,
@@ -2053,6 +2069,7 @@ export const bgBG: LocalizationResource = {
20532069
protect_check_timed_out: undefined,
20542070
protect_check_unsupported_environment: undefined,
20552071
session_exists: 'Вече сте влезнали.',
2072+
sso_bypass_domain_not_served: undefined,
20562073
ticket_expired_code: undefined,
20572074
ticket_invalid_code: undefined,
20582075
web3_missing_identifier: undefined,

‎packages/localizations/src/bn-IN.ts‎

Lines changed: 21 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1389,14 +1389,30 @@ export const bnIN: LocalizationResource = {
13891389
action__add: undefined,
13901390
action__search: undefined,
13911391
addForm: {
1392-
changeButton: undefined,
1393-
memberLabel: undefined,
1394-
memberPlaceholder: undefined,
1395-
noResults: undefined,
1392+
emailPlaceholder: undefined,
1393+
error__allAlreadyAdded: undefined,
1394+
error__alreadyAdded: undefined,
1395+
error__memberNotFound: undefined,
1396+
modeLabel: undefined,
1397+
mode__email: undefined,
1398+
mode__role: undefined,
1399+
roleOption: undefined,
1400+
roleWarning: undefined,
13961401
submitButton: undefined,
13971402
subtitle: undefined,
13981403
title: undefined,
13991404
},
1405+
bulkResult: {
1406+
added: undefined,
1407+
addedMember: undefined,
1408+
added__one: undefined,
1409+
domainNotServed: undefined,
1410+
domainNotServed__one: undefined,
1411+
notMember: undefined,
1412+
notMember__one: undefined,
1413+
unknown: undefined,
1414+
unknown__one: undefined,
1415+
},
14001416
table: {
14011417
emptyState: undefined,
14021418
emptyState__search: undefined,
@@ -2078,6 +2094,7 @@ export const bnIN: LocalizationResource = {
20782094
protect_check_timed_out: undefined,
20792095
protect_check_unsupported_environment: undefined,
20802096
session_exists: undefined,
2097+
sso_bypass_domain_not_served: undefined,
20812098
ticket_expired_code: undefined,
20822099
ticket_invalid_code: undefined,
20832100
web3_missing_identifier: 'একটি Web3 ওয়ালেট এক্সটেনশন পাওয়া যায়নি। চালিয়ে যেতে দয়া করে একটি ইনস্টল করুন।',

‎packages/localizations/src/ca-ES.ts‎

Lines changed: 21 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1389,14 +1389,30 @@ export const caES: LocalizationResource = {
13891389
action__add: undefined,
13901390
action__search: undefined,
13911391
addForm: {
1392-
changeButton: undefined,
1393-
memberLabel: undefined,
1394-
memberPlaceholder: undefined,
1395-
noResults: undefined,
1392+
emailPlaceholder: undefined,
1393+
error__allAlreadyAdded: undefined,
1394+
error__alreadyAdded: undefined,
1395+
error__memberNotFound: undefined,
1396+
modeLabel: undefined,
1397+
mode__email: undefined,
1398+
mode__role: undefined,
1399+
roleOption: undefined,
1400+
roleWarning: undefined,
13961401
submitButton: undefined,
13971402
subtitle: undefined,
13981403
title: undefined,
13991404
},
1405+
bulkResult: {
1406+
added: undefined,
1407+
addedMember: undefined,
1408+
added__one: undefined,
1409+
domainNotServed: undefined,
1410+
domainNotServed__one: undefined,
1411+
notMember: undefined,
1412+
notMember__one: undefined,
1413+
unknown: undefined,
1414+
unknown__one: undefined,
1415+
},
14001416
table: {
14011417
emptyState: undefined,
14021418
emptyState__search: undefined,
@@ -2066,6 +2082,7 @@ export const caES: LocalizationResource = {
20662082
protect_check_timed_out: undefined,
20672083
protect_check_unsupported_environment: undefined,
20682084
session_exists: 'Ja estàs connectat.',
2085+
sso_bypass_domain_not_served: undefined,
20692086
ticket_expired_code: undefined,
20702087
ticket_invalid_code: undefined,
20712088
web3_missing_identifier: undefined,

‎packages/localizations/src/cs-CZ.ts‎

Lines changed: 21 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1387,14 +1387,30 @@ export const csCZ: LocalizationResource = {
13871387
action__add: undefined,
13881388
action__search: undefined,
13891389
addForm: {
1390-
changeButton: undefined,
1391-
memberLabel: undefined,
1392-
memberPlaceholder: undefined,
1393-
noResults: undefined,
1390+
emailPlaceholder: undefined,
1391+
error__allAlreadyAdded: undefined,
1392+
error__alreadyAdded: undefined,
1393+
error__memberNotFound: undefined,
1394+
modeLabel: undefined,
1395+
mode__email: undefined,
1396+
mode__role: undefined,
1397+
roleOption: undefined,
1398+
roleWarning: undefined,
13941399
submitButton: undefined,
13951400
subtitle: undefined,
13961401
title: undefined,
13971402
},
1403+
bulkResult: {
1404+
added: undefined,
1405+
addedMember: undefined,
1406+
added__one: undefined,
1407+
domainNotServed: undefined,
1408+
domainNotServed__one: undefined,
1409+
notMember: undefined,
1410+
notMember__one: undefined,
1411+
unknown: undefined,
1412+
unknown__one: undefined,
1413+
},
13981414
table: {
13991415
emptyState: undefined,
14001416
emptyState__search: undefined,
@@ -2065,6 +2081,7 @@ export const csCZ: LocalizationResource = {
20652081
protect_check_timed_out: undefined,
20662082
protect_check_unsupported_environment: undefined,
20672083
session_exists: 'Jste již přihlášen.',
2084+
sso_bypass_domain_not_served: undefined,
20682085
ticket_expired_code: undefined,
20692086
ticket_invalid_code: undefined,
20702087
web3_missing_identifier: 'Rozšíření peněženky Web3 nebylo nalezeno. Pro pokračování prosím nainstalujte jednu.',

0 commit comments

Comments
 (0)