keycloakify 11.5.3 → 11.6.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 (36) hide show
  1. package/bin/{682.index.js → 153.index.js} +300 -52
  2. package/bin/356.index.js +48 -25
  3. package/bin/{573.index.js → 880.index.js} +155 -9
  4. package/bin/main.js +6 -5
  5. package/bin/start-keycloak/realmConfig/{ParsedRealmJson.d.ts → ParsedRealmJson/ParsedRealmJson.d.ts} +2 -3
  6. package/bin/start-keycloak/realmConfig/ParsedRealmJson/index.d.ts +3 -0
  7. package/bin/start-keycloak/realmConfig/ParsedRealmJson/readRealmJsonFile.d.ts +4 -0
  8. package/bin/start-keycloak/realmConfig/ParsedRealmJson/writeRealmJsonFile.d.ts +6 -0
  9. package/bin/start-keycloak/realmConfig/defaultConfig/defaultConfig.d.ts +1 -4
  10. package/bin/tools/Stringifyable.d.ts +13 -0
  11. package/bin/tools/canonicalStringify.d.ts +5 -0
  12. package/bin/tools/createObjectThatThrowsIfAccessed.d.ts +21 -0
  13. package/package.json +18 -5
  14. package/src/bin/keycloakify/generateResources/generateResources.ts +162 -6
  15. package/src/bin/main.ts +4 -3
  16. package/src/bin/postinstall/getUiModuleFileSourceCodeReadyToBeCopied.ts +63 -24
  17. package/src/bin/start-keycloak/realmConfig/{ParsedRealmJson.ts → ParsedRealmJson/ParsedRealmJson.ts} +1 -19
  18. package/src/bin/start-keycloak/realmConfig/ParsedRealmJson/index.ts +3 -0
  19. package/src/bin/start-keycloak/realmConfig/ParsedRealmJson/readRealmJsonFile.ts +20 -0
  20. package/src/bin/start-keycloak/realmConfig/ParsedRealmJson/writeRealmJsonFile.ts +29 -0
  21. package/src/bin/start-keycloak/realmConfig/defaultConfig/defaultConfig.ts +3 -4
  22. package/src/bin/start-keycloak/realmConfig/defaultConfig/realm-kc-18.json +51 -33
  23. package/src/bin/start-keycloak/realmConfig/defaultConfig/realm-kc-19.json +48 -30
  24. package/src/bin/start-keycloak/realmConfig/defaultConfig/realm-kc-20.json +50 -32
  25. package/src/bin/start-keycloak/realmConfig/defaultConfig/realm-kc-21.json +29 -11
  26. package/src/bin/start-keycloak/realmConfig/defaultConfig/realm-kc-22.json +2201 -0
  27. package/src/bin/start-keycloak/realmConfig/defaultConfig/realm-kc-23.json +25 -7
  28. package/src/bin/start-keycloak/realmConfig/defaultConfig/realm-kc-24.json +26 -8
  29. package/src/bin/start-keycloak/realmConfig/defaultConfig/realm-kc-25.json +26 -8
  30. package/src/bin/start-keycloak/realmConfig/defaultConfig/realm-kc-26.json +11 -11
  31. package/src/bin/start-keycloak/realmConfig/prepareRealmConfig.ts +1 -1
  32. package/src/bin/start-keycloak/realmConfig/realmConfig.ts +15 -19
  33. package/src/bin/start-keycloak/start-keycloak.ts +131 -36
  34. package/src/bin/tools/Stringifyable.ts +99 -0
  35. package/src/bin/tools/canonicalStringify.ts +164 -0
  36. package/src/bin/tools/createObjectThatThrowsIfAccessed.ts +90 -0
@@ -32,38 +32,20 @@ export async function getUiModuleFileSourceCodeReadyToBeCopied(params: {
32
32
  await fsPr.readFile(pathJoin(uiModuleDirPath, KEYCLOAK_THEME, fileRelativePath))
33
33
  ).toString("utf8");
34
34
 
35
- const toComment = (lines: string[]) => {
36
- for (const ext of [".ts", ".tsx", ".css", ".less", ".sass", ".js", ".jsx"]) {
37
- if (!fileRelativePath.endsWith(ext)) {
38
- continue;
39
- }
40
-
41
- return [`/**`, ...lines.map(line => ` * ${line}`), ` */`].join("\n");
42
- }
43
-
44
- if (fileRelativePath.endsWith(".html")) {
45
- return [`<!--`, ...lines.map(line => ` ${line}`), `-->`].join("\n");
46
- }
47
-
48
- return undefined;
49
- };
50
-
51
- const comment = toComment(
52
- isForEjection
35
+ sourceCode = addCommentToSourceCode({
36
+ sourceCode,
37
+ fileRelativePath,
38
+ commentLines: isForEjection
53
39
  ? [`This file was ejected from ${uiModuleName} version ${uiModuleVersion}.`]
54
40
  : [
55
41
  `WARNING: Before modifying this file run the following command:`,
56
42
  ``,
57
- `$ npx keycloakify eject-file --file ${fileRelativePath.split(pathSep).join("/")}`,
43
+ `$ npx keycloakify eject-file --file '${fileRelativePath.split(pathSep).join("/")}'`,
58
44
  ``,
59
45
  `This file comes from ${uiModuleName} version ${uiModuleVersion}.`,
60
46
  `This file has been copied over to your repo by your postinstall script: \`npx keycloakify postinstall\``
61
47
  ]
62
- );
63
-
64
- if (comment !== undefined) {
65
- sourceCode = [comment, ``, sourceCode].join("\n");
66
- }
48
+ });
67
49
 
68
50
  const destFilePath = pathJoin(buildContext.themeSrcDirPath, fileRelativePath);
69
51
 
@@ -80,3 +62,60 @@ export async function getUiModuleFileSourceCodeReadyToBeCopied(params: {
80
62
 
81
63
  return Buffer.from(sourceCode, "utf8");
82
64
  }
65
+
66
+ function addCommentToSourceCode(params: {
67
+ sourceCode: string;
68
+ fileRelativePath: string;
69
+ commentLines: string[];
70
+ }): string {
71
+ const { sourceCode, fileRelativePath, commentLines } = params;
72
+
73
+ const toResult = (comment: string) => {
74
+ return [comment, ``, sourceCode].join("\n");
75
+ };
76
+
77
+ for (const ext of [".ts", ".tsx", ".css", ".less", ".sass", ".js", ".jsx"]) {
78
+ if (!fileRelativePath.endsWith(ext)) {
79
+ continue;
80
+ }
81
+
82
+ return toResult(
83
+ [`/**`, ...commentLines.map(line => ` * ${line}`), ` */`].join("\n")
84
+ );
85
+ }
86
+
87
+ if (fileRelativePath.endsWith(".properties")) {
88
+ return toResult(commentLines.map(line => `# ${line}`).join("\n"));
89
+ }
90
+
91
+ if (fileRelativePath.endsWith(".html") || fileRelativePath.endsWith(".svg")) {
92
+ const comment = [
93
+ `<!--`,
94
+ ...commentLines.map(
95
+ line =>
96
+ ` ${line.replace("--file", "-f").replace("Before modifying", "Before modifying or replacing")}`
97
+ ),
98
+ `-->`
99
+ ].join("\n");
100
+
101
+ if (fileRelativePath.endsWith(".html") && sourceCode.trim().startsWith("<!")) {
102
+ const [first, ...rest] = sourceCode.split(">");
103
+
104
+ const last = rest.join(">");
105
+
106
+ return [`${first}>`, comment, last].join("\n");
107
+ }
108
+
109
+ if (fileRelativePath.endsWith(".svg") && sourceCode.trim().startsWith("<?")) {
110
+ const [first, ...rest] = sourceCode.split("?>");
111
+
112
+ const last = rest.join("?>");
113
+
114
+ return [`${first}?>`, comment, last].join("\n");
115
+ }
116
+
117
+ return toResult(comment);
118
+ }
119
+
120
+ return sourceCode;
121
+ }
@@ -1,8 +1,6 @@
1
1
  import { z } from "zod";
2
2
  import { assert, type Equals } from "tsafe/assert";
3
- import { is } from "tsafe/is";
4
3
  import { id } from "tsafe/id";
5
- import * as fs from "fs";
6
4
 
7
5
  export type ParsedRealmJson = {
8
6
  realm: string;
@@ -50,7 +48,7 @@ export type ParsedRealmJson = {
50
48
  }[];
51
49
  };
52
50
 
53
- const zParsedRealmJson = (() => {
51
+ export const zParsedRealmJson = (() => {
54
52
  type TargetType = ParsedRealmJson;
55
53
 
56
54
  const zTargetType = z.object({
@@ -118,19 +116,3 @@ const zParsedRealmJson = (() => {
118
116
 
119
117
  return id<z.ZodType<TargetType>>(zTargetType);
120
118
  })();
121
-
122
- export function readRealmJsonFile(params: {
123
- realmJsonFilePath: string;
124
- }): ParsedRealmJson {
125
- const { realmJsonFilePath } = params;
126
-
127
- const parsedRealmJson = JSON.parse(
128
- fs.readFileSync(realmJsonFilePath).toString("utf8")
129
- ) as unknown;
130
-
131
- zParsedRealmJson.parse(parsedRealmJson);
132
-
133
- assert(is<ParsedRealmJson>(parsedRealmJson));
134
-
135
- return parsedRealmJson;
136
- }
@@ -0,0 +1,3 @@
1
+ export type { ParsedRealmJson } from "./ParsedRealmJson";
2
+ export { readRealmJsonFile } from "./readRealmJsonFile";
3
+ export { writeRealmJsonFile } from "./writeRealmJsonFile";
@@ -0,0 +1,20 @@
1
+ import { assert } from "tsafe/assert";
2
+ import { is } from "tsafe/is";
3
+ import * as fs from "fs";
4
+ import { type ParsedRealmJson, zParsedRealmJson } from "./ParsedRealmJson";
5
+
6
+ export function readRealmJsonFile(params: {
7
+ realmJsonFilePath: string;
8
+ }): ParsedRealmJson {
9
+ const { realmJsonFilePath } = params;
10
+
11
+ const parsedRealmJson = JSON.parse(
12
+ fs.readFileSync(realmJsonFilePath).toString("utf8")
13
+ ) as unknown;
14
+
15
+ zParsedRealmJson.parse(parsedRealmJson);
16
+
17
+ assert(is<ParsedRealmJson>(parsedRealmJson));
18
+
19
+ return parsedRealmJson;
20
+ }
@@ -0,0 +1,29 @@
1
+ import * as fsPr from "fs/promises";
2
+ import { getIsPrettierAvailable, runPrettier } from "../../../tools/runPrettier";
3
+ import { canonicalStringify } from "../../../tools/canonicalStringify";
4
+ import type { ParsedRealmJson } from "./ParsedRealmJson";
5
+ import { getDefaultConfig } from "../defaultConfig";
6
+
7
+ export async function writeRealmJsonFile(params: {
8
+ realmJsonFilePath: string;
9
+ parsedRealmJson: ParsedRealmJson;
10
+ keycloakMajorVersionNumber: number;
11
+ }): Promise<void> {
12
+ const { realmJsonFilePath, parsedRealmJson, keycloakMajorVersionNumber } = params;
13
+
14
+ let sourceCode = canonicalStringify({
15
+ data: parsedRealmJson,
16
+ referenceData: getDefaultConfig({
17
+ keycloakMajorVersionNumber
18
+ })
19
+ });
20
+
21
+ if (await getIsPrettierAvailable()) {
22
+ sourceCode = await runPrettier({
23
+ sourceCode: sourceCode,
24
+ filePath: realmJsonFilePath
25
+ });
26
+ }
27
+
28
+ await fsPr.writeFile(realmJsonFilePath, Buffer.from(sourceCode, "utf8"));
29
+ }
@@ -3,11 +3,10 @@ import { getThisCodebaseRootDirPath } from "../../../tools/getThisCodebaseRootDi
3
3
  import * as fs from "fs";
4
4
  import { exclude } from "tsafe/exclude";
5
5
  import { assert } from "tsafe/assert";
6
- import { type ParsedRealmJson, readRealmJsonFile } from "../ParsedRealmJson";
6
+ import { readRealmJsonFile } from "../ParsedRealmJson/readRealmJsonFile";
7
+ import type { ParsedRealmJson } from "../ParsedRealmJson/ParsedRealmJson";
7
8
 
8
- export function getDefaultRealmJsonFilePath(params: {
9
- keycloakMajorVersionNumber: number;
10
- }) {
9
+ function getDefaultRealmJsonFilePath(params: { keycloakMajorVersionNumber: number }) {
11
10
  const { keycloakMajorVersionNumber } = params;
12
11
 
13
12
  return pathJoin(
@@ -756,6 +756,24 @@
756
756
  "fullScopeAllowed": false,
757
757
  "nodeReRegistrationTimeout": 0,
758
758
  "protocolMappers": [
759
+ {
760
+ "id": "8fd0d584-7052-4d04-a615-d18a71050873",
761
+ "name": "allowed-origins",
762
+ "protocol": "openid-connect",
763
+ "protocolMapper": "oidc-hardcoded-claim-mapper",
764
+ "consentRequired": false,
765
+ "config": {
766
+ "userinfo.token.claim": "true",
767
+ "id.token.claim": "false",
768
+ "access.token.claim": "true",
769
+ "claim.name": "allowed-origins",
770
+ "jsonType.label": "JSON",
771
+ "access.tokenResponse.claim": "false",
772
+ "claim.value": "[\"*\"]",
773
+ "introspection.token.claim": "true",
774
+ "lightweight.claim": "true"
775
+ }
776
+ },
759
777
  {
760
778
  "id": "7779f8fa-c2fe-4e68-be56-66ee97bf8f13",
761
779
  "name": "locale",
@@ -1336,13 +1354,13 @@
1336
1354
  "subComponents": {},
1337
1355
  "config": {
1338
1356
  "allowed-protocol-mapper-types": [
1339
- "saml-user-attribute-mapper",
1340
- "oidc-usermodel-property-mapper",
1341
- "oidc-full-name-mapper",
1342
1357
  "saml-user-property-mapper",
1343
- "oidc-usermodel-attribute-mapper",
1344
- "oidc-address-mapper",
1345
1358
  "oidc-sha256-pairwise-sub-mapper",
1359
+ "oidc-address-mapper",
1360
+ "oidc-full-name-mapper",
1361
+ "oidc-usermodel-attribute-mapper",
1362
+ "saml-user-attribute-mapper",
1363
+ "oidc-usermodel-property-mapper",
1346
1364
  "saml-role-list-mapper"
1347
1365
  ]
1348
1366
  }
@@ -1393,13 +1411,13 @@
1393
1411
  "config": {
1394
1412
  "allowed-protocol-mapper-types": [
1395
1413
  "oidc-full-name-mapper",
1396
- "oidc-usermodel-property-mapper",
1397
- "saml-user-property-mapper",
1398
- "oidc-usermodel-attribute-mapper",
1399
- "oidc-sha256-pairwise-sub-mapper",
1400
- "saml-role-list-mapper",
1401
1414
  "oidc-address-mapper",
1402
- "saml-user-attribute-mapper"
1415
+ "saml-role-list-mapper",
1416
+ "oidc-sha256-pairwise-sub-mapper",
1417
+ "saml-user-attribute-mapper",
1418
+ "saml-user-property-mapper",
1419
+ "oidc-usermodel-property-mapper",
1420
+ "oidc-usermodel-attribute-mapper"
1403
1421
  ]
1404
1422
  }
1405
1423
  },
@@ -1517,7 +1535,7 @@
1517
1535
  "defaultLocale": "en",
1518
1536
  "authenticationFlows": [
1519
1537
  {
1520
- "id": "223ce532-2038-4f24-a606-2a5c73f7bd65",
1538
+ "id": "f664efe4-102d-4ec1-bf11-11af67e3f178",
1521
1539
  "alias": "Account verification options",
1522
1540
  "description": "Method with which to verity the existing account",
1523
1541
  "providerId": "basic-flow",
@@ -1543,7 +1561,7 @@
1543
1561
  ]
1544
1562
  },
1545
1563
  {
1546
- "id": "57e47732-79cc-4d60-bee7-4f0b8fd44540",
1564
+ "id": "8a5630c5-eca1-4b6a-8e59-459cb6c84535",
1547
1565
  "alias": "Authentication Options",
1548
1566
  "description": "Authentication options.",
1549
1567
  "providerId": "basic-flow",
@@ -1577,7 +1595,7 @@
1577
1595
  ]
1578
1596
  },
1579
1597
  {
1580
- "id": "c2735d89-60c0-45a4-9b3c-ae5df17df395",
1598
+ "id": "c1a3eed3-25ce-44ae-93d1-f0b8148a0f8c",
1581
1599
  "alias": "Browser - Conditional OTP",
1582
1600
  "description": "Flow to determine if the OTP is required for the authentication",
1583
1601
  "providerId": "basic-flow",
@@ -1603,7 +1621,7 @@
1603
1621
  ]
1604
1622
  },
1605
1623
  {
1606
- "id": "11a5a507-2b9a-443f-961b-dffd66f4318d",
1624
+ "id": "6eb188ad-1041-44dd-bf8f-37cae0d98bf1",
1607
1625
  "alias": "Direct Grant - Conditional OTP",
1608
1626
  "description": "Flow to determine if the OTP is required for the authentication",
1609
1627
  "providerId": "basic-flow",
@@ -1629,7 +1647,7 @@
1629
1647
  ]
1630
1648
  },
1631
1649
  {
1632
- "id": "963bd753-6ea7-4d93-ab56-30f9ab59d597",
1650
+ "id": "4ee215ac-f4e5-4edb-bf76-65dc9e211543",
1633
1651
  "alias": "First broker login - Conditional OTP",
1634
1652
  "description": "Flow to determine if the OTP is required for the authentication",
1635
1653
  "providerId": "basic-flow",
@@ -1655,7 +1673,7 @@
1655
1673
  ]
1656
1674
  },
1657
1675
  {
1658
- "id": "1db6a489-a3b4-44c4-b480-1d1e8c123d20",
1676
+ "id": "5a1eac7e-06a0-46d8-b9ae-1f2c934331f9",
1659
1677
  "alias": "Handle Existing Account",
1660
1678
  "description": "Handle what to do if there is existing account with same email/username like authenticated identity provider",
1661
1679
  "providerId": "basic-flow",
@@ -1681,7 +1699,7 @@
1681
1699
  ]
1682
1700
  },
1683
1701
  {
1684
- "id": "7a38f32d-4f34-450f-8f03-64802d7cb8f1",
1702
+ "id": "ed165166-4521-4a62-b185-c4b51643cbb1",
1685
1703
  "alias": "Reset - Conditional OTP",
1686
1704
  "description": "Flow to determine if the OTP should be reset or not. Set to REQUIRED to force.",
1687
1705
  "providerId": "basic-flow",
@@ -1707,7 +1725,7 @@
1707
1725
  ]
1708
1726
  },
1709
1727
  {
1710
- "id": "0df88739-3739-4d70-8893-47c546f19003",
1728
+ "id": "4788fb1f-fd81-4f5d-9abe-4199dd641c1e",
1711
1729
  "alias": "User creation or linking",
1712
1730
  "description": "Flow for the existing/non-existing user alternatives",
1713
1731
  "providerId": "basic-flow",
@@ -1734,7 +1752,7 @@
1734
1752
  ]
1735
1753
  },
1736
1754
  {
1737
- "id": "35025424-e291-4c54-8a29-70aadba549ce",
1755
+ "id": "d778a70f-f472-4dd3-ac40-cb5612ddc171",
1738
1756
  "alias": "Verify Existing Account by Re-authentication",
1739
1757
  "description": "Reauthentication of existing account",
1740
1758
  "providerId": "basic-flow",
@@ -1760,7 +1778,7 @@
1760
1778
  ]
1761
1779
  },
1762
1780
  {
1763
- "id": "1813b7f2-c3c2-4b92-8ffc-9ff2d12186c6",
1781
+ "id": "9c1ea8ea-7c23-4e60-b02d-1900d9dc4109",
1764
1782
  "alias": "browser",
1765
1783
  "description": "browser based authentication",
1766
1784
  "providerId": "basic-flow",
@@ -1802,7 +1820,7 @@
1802
1820
  ]
1803
1821
  },
1804
1822
  {
1805
- "id": "954283ac-f1c2-40b6-a39f-bf23ff9f3ce8",
1823
+ "id": "0ebdf418-d57d-4318-9359-7bd0cb2381f2",
1806
1824
  "alias": "clients",
1807
1825
  "description": "Base authentication for clients",
1808
1826
  "providerId": "client-flow",
@@ -1844,7 +1862,7 @@
1844
1862
  ]
1845
1863
  },
1846
1864
  {
1847
- "id": "52a789ce-2cad-4f0f-93b2-295b7fd519f0",
1865
+ "id": "5cc89293-c72e-4c5e-b31c-15558588a60d",
1848
1866
  "alias": "direct grant",
1849
1867
  "description": "OpenID Connect Resource Owner Grant",
1850
1868
  "providerId": "basic-flow",
@@ -1878,7 +1896,7 @@
1878
1896
  ]
1879
1897
  },
1880
1898
  {
1881
- "id": "5a6a71e1-9105-45b6-b5f0-52538461357b",
1899
+ "id": "5ae5a321-ccac-449e-9c19-d6dc22ab8085",
1882
1900
  "alias": "docker auth",
1883
1901
  "description": "Used by Docker clients to authenticate against the IDP",
1884
1902
  "providerId": "basic-flow",
@@ -1896,7 +1914,7 @@
1896
1914
  ]
1897
1915
  },
1898
1916
  {
1899
- "id": "8392b6e7-bdbf-4d7f-97b6-885761c200db",
1917
+ "id": "7737fdd1-0875-47e6-977b-12561cddfdc3",
1900
1918
  "alias": "first broker login",
1901
1919
  "description": "Actions taken after first broker login with identity provider account, which is not yet linked to any Keycloak account",
1902
1920
  "providerId": "basic-flow",
@@ -1923,7 +1941,7 @@
1923
1941
  ]
1924
1942
  },
1925
1943
  {
1926
- "id": "52136d70-8d08-42ea-b04b-cf40ea2807aa",
1944
+ "id": "90f975c3-9826-461f-88ca-27c697aff86b",
1927
1945
  "alias": "forms",
1928
1946
  "description": "Username, password, otp and other auth forms.",
1929
1947
  "providerId": "basic-flow",
@@ -1949,7 +1967,7 @@
1949
1967
  ]
1950
1968
  },
1951
1969
  {
1952
- "id": "26bbc7e6-ef01-4cdb-9dba-520e2f3f8993",
1970
+ "id": "ce2722d5-9f4f-41a2-8f81-e01f7b6cee57",
1953
1971
  "alias": "http challenge",
1954
1972
  "description": "An authentication flow based on challenge-response HTTP Authentication Schemes",
1955
1973
  "providerId": "basic-flow",
@@ -1975,7 +1993,7 @@
1975
1993
  ]
1976
1994
  },
1977
1995
  {
1978
- "id": "f0887979-04eb-4033-8f19-0ffd8c8b7f6a",
1996
+ "id": "31b5bfa7-98ad-47a2-b8e6-0669022cd8cb",
1979
1997
  "alias": "registration",
1980
1998
  "description": "registration flow",
1981
1999
  "providerId": "basic-flow",
@@ -1994,7 +2012,7 @@
1994
2012
  ]
1995
2013
  },
1996
2014
  {
1997
- "id": "a3b7b94b-bfbf-4760-a8c9-7d9cd98d262e",
2015
+ "id": "bf8a950b-be3b-4e44-8602-64e0bba492eb",
1998
2016
  "alias": "registration form",
1999
2017
  "description": "registration form",
2000
2018
  "providerId": "form-flow",
@@ -2036,7 +2054,7 @@
2036
2054
  ]
2037
2055
  },
2038
2056
  {
2039
- "id": "dc68a665-2e51-4a22-aaad-bd693ddc77cc",
2057
+ "id": "e3519800-971b-4b1d-b64e-3983ccd02dea",
2040
2058
  "alias": "reset credentials",
2041
2059
  "description": "Reset credentials for a user if they forgot their password or something",
2042
2060
  "providerId": "basic-flow",
@@ -2078,7 +2096,7 @@
2078
2096
  ]
2079
2097
  },
2080
2098
  {
2081
- "id": "ae6b73aa-1318-4ae8-a3d9-d01b5e7d957e",
2099
+ "id": "9d5a33a2-e777-4beb-95de-b84812f69c56",
2082
2100
  "alias": "saml ecp",
2083
2101
  "description": "SAML ECP Profile Authentication Flow",
2084
2102
  "providerId": "basic-flow",
@@ -2098,14 +2116,14 @@
2098
2116
  ],
2099
2117
  "authenticatorConfig": [
2100
2118
  {
2101
- "id": "0c18de7f-0714-41f4-9a3f-ed4edd53ae9c",
2119
+ "id": "4901c91d-59bd-4727-b585-8e4e44828d0a",
2102
2120
  "alias": "create unique user config",
2103
2121
  "config": {
2104
2122
  "require.password.update.after.registration": "false"
2105
2123
  }
2106
2124
  },
2107
2125
  {
2108
- "id": "65b3c8bb-34a4-4d19-b578-245dc8ff53ea",
2126
+ "id": "5062a078-83a7-4933-b0d5-3f75cc2a5003",
2109
2127
  "alias": "review profile config",
2110
2128
  "config": {
2111
2129
  "update.profile.on.first.login": "missing"