@ibgib/web-gib 0.0.49 → 0.0.51

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 (42) hide show
  1. package/dist/AUTO-GENERATED-version.d.mts +1 -1
  2. package/dist/AUTO-GENERATED-version.mjs +1 -1
  3. package/dist/common/settings/settings-constants.d.mts +8 -1
  4. package/dist/common/settings/settings-constants.d.mts.map +1 -1
  5. package/dist/common/settings/settings-constants.mjs +7 -0
  6. package/dist/common/settings/settings-constants.mjs.map +1 -1
  7. package/dist/common/settings/settings-helpers.d.mts.map +1 -1
  8. package/dist/common/settings/settings-helpers.mjs +3 -1
  9. package/dist/common/settings/settings-helpers.mjs.map +1 -1
  10. package/dist/common/settings/settings-types.d.mts +5 -2
  11. package/dist/common/settings/settings-types.d.mts.map +1 -1
  12. package/dist/identity/sso/sso-config-helper.d.mts +7 -0
  13. package/dist/identity/sso/sso-config-helper.d.mts.map +1 -0
  14. package/dist/identity/sso/sso-config-helper.mjs +42 -0
  15. package/dist/identity/sso/sso-config-helper.mjs.map +1 -0
  16. package/dist/identity/sso/sso-custodian-service.d.mts +139 -0
  17. package/dist/identity/sso/sso-custodian-service.d.mts.map +1 -0
  18. package/dist/identity/sso/sso-custodian-service.mjs +443 -0
  19. package/dist/identity/sso/sso-custodian-service.mjs.map +1 -0
  20. package/dist/identity/sso/sso-custodian-service.respec.d.mts +2 -0
  21. package/dist/identity/sso/sso-custodian-service.respec.d.mts.map +1 -0
  22. package/dist/identity/sso/sso-custodian-service.respec.mjs +254 -0
  23. package/dist/identity/sso/sso-custodian-service.respec.mjs.map +1 -0
  24. package/dist/identity/sso/sso-helpers.d.mts +10 -0
  25. package/dist/identity/sso/sso-helpers.d.mts.map +1 -0
  26. package/dist/identity/sso/sso-helpers.mjs +11 -0
  27. package/dist/identity/sso/sso-helpers.mjs.map +1 -0
  28. package/dist/identity/sso/sso-types.d.mts +40 -0
  29. package/dist/identity/sso/sso-types.d.mts.map +1 -0
  30. package/dist/identity/sso/sso-types.mjs +7 -0
  31. package/dist/identity/sso/sso-types.mjs.map +1 -0
  32. package/package.json +4 -3
  33. package/src/AUTO-GENERATED-version.mts +1 -1
  34. package/src/common/settings/settings-constants.mts +9 -0
  35. package/src/common/settings/settings-helpers.mts +4 -1
  36. package/src/common/settings/settings-types.mts +7 -2
  37. package/src/identity/sso/sso-config-helper.mts +52 -0
  38. package/src/identity/sso/sso-custodian-service.mts +539 -0
  39. package/src/identity/sso/sso-custodian-service.respec.mts +297 -0
  40. package/src/identity/sso/sso-helpers.mts +17 -0
  41. package/src/identity/sso/sso-types.mts +44 -0
  42. package/src/ui/component/README.md +53 -1
@@ -0,0 +1,254 @@
1
+ import { generateKeyPairSync, createSign } from 'node:crypto';
2
+ import { respecfully, ifWeMight, iReckon, firstOfAll, lastOfAll } from '@ibgib/helper-gib/dist/respec-gib/respec-gib.mjs';
3
+ import { SsoCustodianService } from './sso-custodian-service.mjs';
4
+ import { POOL_ID_MANAGE } from '@ibgib/core-gib/dist/keystone/keystone-constants.mjs';
5
+ import { createStandardPoolConfig } from '@ibgib/core-gib/dist/keystone/keystone-config-builder.mjs';
6
+ const maam = `[${import.meta.url}]`, sir = maam;
7
+ await respecfully(sir, 'SsoCustodianService', async () => {
8
+ let mockPrivateKey;
9
+ let mockPublicKeyJwk;
10
+ let originalFetch;
11
+ firstOfAll(sir, async () => {
12
+ // Generate mock RSA key pair
13
+ const { privateKey, publicKey } = generateKeyPairSync('rsa', {
14
+ modulusLength: 2048
15
+ });
16
+ mockPrivateKey = privateKey;
17
+ // Export public key as JWK
18
+ mockPublicKeyJwk = publicKey.export({ format: 'jwk' });
19
+ mockPublicKeyJwk.kid = 'mock-kid-123';
20
+ mockPublicKeyJwk.alg = 'RS256';
21
+ mockPublicKeyJwk.use = 'sig';
22
+ // Mock global fetch to return JWKS containing the mock public key
23
+ originalFetch = globalThis.fetch;
24
+ globalThis.fetch = async (url, options) => {
25
+ if (url === 'https://www.googleapis.com/oauth2/v3/certs') {
26
+ return {
27
+ ok: true,
28
+ status: 200,
29
+ json: async () => ({
30
+ keys: [mockPublicKeyJwk]
31
+ })
32
+ };
33
+ }
34
+ return {
35
+ ok: false,
36
+ status: 404,
37
+ text: async () => 'Not Found'
38
+ };
39
+ };
40
+ });
41
+ lastOfAll(sir, async () => {
42
+ // Restore global fetch
43
+ if (originalFetch) {
44
+ globalThis.fetch = originalFetch;
45
+ }
46
+ });
47
+ await ifWeMight(sir, 'verify dynamic RSA RS256 JWT signature successfully', async () => {
48
+ const config = {
49
+ ssoServerKdfSecret: 'mock-kdf-secret',
50
+ sessionSecret: 'mock-session-secret',
51
+ providers: {
52
+ google: {
53
+ providerId: 'google',
54
+ clientId: 'google-client-id-123',
55
+ clientSecret: 'google-client-secret-123',
56
+ tokenUrl: 'https://oauth2.googleapis.com/token',
57
+ userInfoUrl: 'https://openidconnect.googleapis.com/v1/userinfo',
58
+ jwksUrl: 'https://www.googleapis.com/oauth2/v3/certs'
59
+ }
60
+ }
61
+ };
62
+ const service = new SsoCustodianService(config);
63
+ // 1. Build JWT Header & Payload
64
+ const header = { alg: 'RS256', kid: 'mock-kid-123', typ: 'JWT' };
65
+ const payload = {
66
+ sub: 'user-sub-999',
67
+ email: 'user@example.com',
68
+ name: 'John Doe',
69
+ aud: 'google-client-id-123',
70
+ iss: 'https://accounts.google.com',
71
+ exp: Math.floor(Date.now() / 1000) + 3600 // expires in 1 hour
72
+ };
73
+ const headerB64 = Buffer.from(JSON.stringify(header)).toString('base64url');
74
+ const payloadB64 = Buffer.from(JSON.stringify(payload)).toString('base64url');
75
+ const data = `${headerB64}.${payloadB64}`;
76
+ // 2. Sign JWT using private key
77
+ const sign = createSign('RSA-SHA256');
78
+ sign.update(data);
79
+ const signatureB64 = sign.sign(mockPrivateKey, 'base64url');
80
+ const mockJwtToken = `${data}.${signatureB64}`;
81
+ // 3. Verify signature via service
82
+ const decodedPayload = await service.verifyJwt(mockJwtToken, config.providers.google);
83
+ iReckon(sir, decodedPayload.sub).isGonnaBe('user-sub-999');
84
+ iReckon(sir, decodedPayload.email).isGonnaBe('user@example.com');
85
+ iReckon(sir, decodedPayload.name).isGonnaBe('John Doe');
86
+ });
87
+ await ifWeMight(sir, 'fail validation if JWT has invalid signature', async () => {
88
+ const config = {
89
+ ssoServerKdfSecret: 'mock-kdf-secret',
90
+ sessionSecret: 'mock-session-secret',
91
+ providers: {
92
+ google: {
93
+ providerId: 'google',
94
+ clientId: 'google-client-id-123',
95
+ clientSecret: 'google-client-secret-123',
96
+ tokenUrl: 'https://oauth2.googleapis.com/token',
97
+ userInfoUrl: 'https://openidconnect.googleapis.com/v1/userinfo',
98
+ jwksUrl: 'https://www.googleapis.com/oauth2/v3/certs'
99
+ }
100
+ }
101
+ };
102
+ const service = new SsoCustodianService(config);
103
+ const header = { alg: 'RS256', kid: 'mock-kid-123', typ: 'JWT' };
104
+ const payload = {
105
+ sub: 'user-sub-999',
106
+ aud: 'google-client-id-123',
107
+ exp: Math.floor(Date.now() / 1000) + 3600
108
+ };
109
+ const headerB64 = Buffer.from(JSON.stringify(header)).toString('base64url');
110
+ const payloadB64 = Buffer.from(JSON.stringify(payload)).toString('base64url');
111
+ const data = `${headerB64}.${payloadB64}`;
112
+ // Create signature using a different/unregistered RSA key
113
+ const { privateKey: badPrivateKey } = generateKeyPairSync('rsa', { modulusLength: 2048 });
114
+ const sign = createSign('RSA-SHA256');
115
+ sign.update(data);
116
+ const badSignatureB64 = sign.sign(badPrivateKey, 'base64url');
117
+ const badJwtToken = `${data}.${badSignatureB64}`;
118
+ let verifyError;
119
+ try {
120
+ await service.verifyJwt(badJwtToken, config.providers.google);
121
+ }
122
+ catch (error) {
123
+ verifyError = error;
124
+ }
125
+ iReckon(sir, verifyError).not.isGonnaBeUndefined();
126
+ iReckon(sir, verifyError.message).includes('Cryptographic signature verification failed');
127
+ });
128
+ await ifWeMight(sir, 'derive server-delegate secret deterministically', async () => {
129
+ const config = {
130
+ ssoServerKdfSecret: 'high-entropy-server-kdf-secret',
131
+ sessionSecret: 'session-secret-123',
132
+ providers: {}
133
+ };
134
+ const service = new SsoCustodianService(config);
135
+ const key = 'google:123456789';
136
+ const nonce1 = 'nonce-abc-123';
137
+ const nonce2 = 'nonce-def-456';
138
+ const secret1_a = await service.deriveServerDelegateSecret(key, nonce1);
139
+ const secret1_b = await service.deriveServerDelegateSecret(key, nonce1);
140
+ const secret2 = await service.deriveServerDelegateSecret(key, nonce2);
141
+ // Identical inputs must yield identical outputs
142
+ iReckon(sir, secret1_a).isGonnaBe(secret1_b);
143
+ // Different nonces must yield different outputs
144
+ iReckon(sir, secret1_a).not.isGonnaBe(secret2);
145
+ // Derived secrets must be string type with high entropy
146
+ iReckon(sir, typeof secret1_a).isGonnaBe('string');
147
+ iReckon(sir, secret1_a.length).isGonnaBe(128); // sha512 output in hex/base64 wrap
148
+ });
149
+ await ifWeMight(sir, 'create custodian challenge pool successfully', async () => {
150
+ const config = {
151
+ ssoServerKdfSecret: 'high-entropy-server-kdf-secret',
152
+ sessionSecret: 'session-secret-123',
153
+ providers: {}
154
+ };
155
+ const service = new SsoCustodianService(config);
156
+ const key = 'google:123456789';
157
+ const nonce = 'nonce-abc-123';
158
+ // 1. Create a mock target keystone containing a 'manage' pool
159
+ const userManageConfig = createStandardPoolConfig({
160
+ id: POOL_ID_MANAGE,
161
+ salt: 'user-manage-salt'
162
+ });
163
+ userManageConfig.behavior.size = 12; // custom size for verification
164
+ const mockTargetKeystone = {
165
+ ib: 'keystone^some-tjp-addr',
166
+ gib: 'some-gib-value',
167
+ data: {
168
+ challengePools: [
169
+ {
170
+ id: 'manage',
171
+ config: userManageConfig,
172
+ challenges: { 'chal1': 'val1' }
173
+ }
174
+ ],
175
+ n: 0
176
+ }
177
+ };
178
+ // 2. Mock metaspace and space calls
179
+ const mockSpace = {};
180
+ const mockMetaspace = {
181
+ getLatestAddr: async () => 'latest-keystone-addr',
182
+ get: async () => ({
183
+ success: true,
184
+ ibGibs: [mockTargetKeystone]
185
+ })
186
+ };
187
+ const custodianPool = await service.createCustodianChallengePool({
188
+ providerId: 'google',
189
+ providerKey: key,
190
+ userNonce: nonce,
191
+ keystoneAddr: 'some-tjp-addr',
192
+ metaspace: mockMetaspace,
193
+ space: mockSpace
194
+ });
195
+ iReckon(sir, custodianPool).not.isGonnaBeUndefined();
196
+ iReckon(sir, custodianPool.id).willEqual('custodian-manage-google');
197
+ iReckon(sir, custodianPool.isForeign).isGonnaBeTrue();
198
+ iReckon(sir, custodianPool.metadata?.providerKey).willEqual(key);
199
+ // Replicated behavior size from parent manage pool config
200
+ iReckon(sir, custodianPool.config.behavior.size).willEqual(userManageConfig.behavior.size);
201
+ // Structural validation of challenges
202
+ const challengesCount = Object.keys(custodianPool.challenges).length;
203
+ iReckon(sir, challengesCount).willEqual(custodianPool.config.behavior.size);
204
+ });
205
+ await ifWeMight(sir, 'revoke tokens successfully, making the correct http fetch calls', async () => {
206
+ const config = {
207
+ ssoServerKdfSecret: 'high-entropy-server-kdf-secret',
208
+ sessionSecret: 'session-secret-123',
209
+ providers: {
210
+ google: {
211
+ providerId: 'google',
212
+ clientId: 'google-client-id-abc',
213
+ clientSecret: 'google-client-secret-abc',
214
+ tokenUrl: 'https://oauth2.googleapis.com/token',
215
+ userInfoUrl: 'https://openidconnect.googleapis.com/v1/userinfo'
216
+ },
217
+ github: {
218
+ providerId: 'github',
219
+ clientId: 'github-client-id-xyz',
220
+ clientSecret: 'github-client-secret-xyz',
221
+ tokenUrl: 'https://github.com/login/oauth/access_token',
222
+ userInfoUrl: 'https://api.github.com/user'
223
+ }
224
+ }
225
+ };
226
+ const service = new SsoCustodianService(config);
227
+ const originalFetch = globalThis.fetch;
228
+ let fetchCalls = [];
229
+ globalThis.fetch = (async (url, options) => {
230
+ fetchCalls.push({ url, options });
231
+ return {
232
+ ok: true,
233
+ status: 200,
234
+ text: async () => 'ok'
235
+ };
236
+ });
237
+ try {
238
+ // Revoke Google token
239
+ await service.revokeToken('google', 'google-test-token-123');
240
+ iReckon(sir, fetchCalls.length).willEqual(1);
241
+ iReckon(sir, fetchCalls[0].url).includes('google-test-token-123');
242
+ // Revoke GitHub token
243
+ await service.revokeToken('github', 'github-test-token-456');
244
+ iReckon(sir, fetchCalls.length).willEqual(2);
245
+ iReckon(sir, fetchCalls[1].url).includes('/applications/github-client-id-xyz/grant');
246
+ iReckon(sir, fetchCalls[1].options.method).willEqual('DELETE');
247
+ iReckon(sir, fetchCalls[1].options.headers['Authorization']).includes('Basic');
248
+ }
249
+ finally {
250
+ globalThis.fetch = originalFetch;
251
+ }
252
+ });
253
+ });
254
+ //# sourceMappingURL=sso-custodian-service.respec.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"sso-custodian-service.respec.mjs","sourceRoot":"","sources":["../../../src/identity/sso/sso-custodian-service.respec.mts"],"names":[],"mappings":"AAAA,OAAO,EAAE,mBAAmB,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AAC9D,OAAO,EACH,WAAW,EACX,SAAS,EACT,OAAO,EACP,UAAU,EACV,SAAS,EACZ,MAAM,kDAAkD,CAAC;AAC1D,OAAO,EAAE,mBAAmB,EAAE,MAAM,6BAA6B,CAAC;AAElE,OAAO,EAA4B,cAAc,EAAE,MAAM,sDAAsD,CAAC;AAChH,OAAO,EAAE,wBAAwB,EAAE,MAAM,2DAA2D,CAAC;AAErG,MAAM,IAAI,GAAG,IAAI,MAAM,CAAC,IAAI,CAAC,GAAG,GAAG,EAAE,GAAG,GAAG,IAAI,CAAC;AAEhD,MAAM,WAAW,CAAC,GAAG,EAAE,qBAAqB,EAAE,KAAK,IAAI,EAAE;IACrD,IAAI,cAAmB,CAAC;IACxB,IAAI,gBAAqB,CAAC;IAC1B,IAAI,aAAkB,CAAC;IAEvB,UAAU,CAAC,GAAG,EAAE,KAAK,IAAI,EAAE;QACvB,6BAA6B;QAC7B,MAAM,EAAE,UAAU,EAAE,SAAS,EAAE,GAAG,mBAAmB,CAAC,KAAK,EAAE;YACzD,aAAa,EAAE,IAAI;SACtB,CAAC,CAAC;QACH,cAAc,GAAG,UAAU,CAAC;QAE5B,2BAA2B;QAC3B,gBAAgB,GAAG,SAAS,CAAC,MAAM,CAAC,EAAE,MAAM,EAAE,KAAK,EAAE,CAAC,CAAC;QACvD,gBAAgB,CAAC,GAAG,GAAG,cAAc,CAAC;QACtC,gBAAgB,CAAC,GAAG,GAAG,OAAO,CAAC;QAC/B,gBAAgB,CAAC,GAAG,GAAG,KAAK,CAAC;QAE7B,kEAAkE;QAClE,aAAa,GAAI,UAAkB,CAAC,KAAK,CAAC;QACzC,UAAkB,CAAC,KAAK,GAAG,KAAK,EAAE,GAAW,EAAE,OAAa,EAAE,EAAE;YAC7D,IAAI,GAAG,KAAK,4CAA4C,EAAE,CAAC;gBACvD,OAAO;oBACH,EAAE,EAAE,IAAI;oBACR,MAAM,EAAE,GAAG;oBACX,IAAI,EAAE,KAAK,IAAI,EAAE,CAAC,CAAC;wBACf,IAAI,EAAE,CAAC,gBAAgB,CAAC;qBAC3B,CAAC;iBACE,CAAC;YACb,CAAC;YACD,OAAO;gBACH,EAAE,EAAE,KAAK;gBACT,MAAM,EAAE,GAAG;gBACX,IAAI,EAAE,KAAK,IAAI,EAAE,CAAC,WAAW;aACzB,CAAC;QACb,CAAC,CAAC;IACN,CAAC,CAAC,CAAC;IAEH,SAAS,CAAC,GAAG,EAAE,KAAK,IAAI,EAAE;QACtB,uBAAuB;QACvB,IAAI,aAAa,EAAE,CAAC;YACf,UAAkB,CAAC,KAAK,GAAG,aAAa,CAAC;QAC9C,CAAC;IACL,CAAC,CAAC,CAAC;IAEH,MAAM,SAAS,CAAC,GAAG,EAAE,qDAAqD,EAAE,KAAK,IAAI,EAAE;QACnF,MAAM,MAAM,GAAoB;YAC5B,kBAAkB,EAAE,iBAAiB;YACrC,aAAa,EAAE,qBAAqB;YACpC,SAAS,EAAE;gBACP,MAAM,EAAE;oBACJ,UAAU,EAAE,QAAQ;oBACpB,QAAQ,EAAE,sBAAsB;oBAChC,YAAY,EAAE,0BAA0B;oBACxC,QAAQ,EAAE,qCAAqC;oBAC/C,WAAW,EAAE,kDAAkD;oBAC/D,OAAO,EAAE,4CAA4C;iBACxD;aACJ;SACJ,CAAC;QAEF,MAAM,OAAO,GAAG,IAAI,mBAAmB,CAAC,MAAM,CAAC,CAAC;QAEhD,gCAAgC;QAChC,MAAM,MAAM,GAAG,EAAE,GAAG,EAAE,OAAO,EAAE,GAAG,EAAE,cAAc,EAAE,GAAG,EAAE,KAAK,EAAE,CAAC;QACjE,MAAM,OAAO,GAAG;YACZ,GAAG,EAAE,cAAc;YACnB,KAAK,EAAE,kBAAkB;YACzB,IAAI,EAAE,UAAU;YAChB,GAAG,EAAE,sBAAsB;YAC3B,GAAG,EAAE,6BAA6B;YAClC,GAAG,EAAE,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,GAAG,EAAE,GAAG,IAAI,CAAC,GAAG,IAAI,CAAC,oBAAoB;SACjE,CAAC;QAEF,MAAM,SAAS,GAAG,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,SAAS,CAAC,MAAM,CAAC,CAAC,CAAC,QAAQ,CAAC,WAAW,CAAC,CAAC;QAC5E,MAAM,UAAU,GAAG,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,SAAS,CAAC,OAAO,CAAC,CAAC,CAAC,QAAQ,CAAC,WAAW,CAAC,CAAC;QAC9E,MAAM,IAAI,GAAG,GAAG,SAAS,IAAI,UAAU,EAAE,CAAC;QAE1C,gCAAgC;QAChC,MAAM,IAAI,GAAG,UAAU,CAAC,YAAY,CAAC,CAAC;QACtC,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC;QAClB,MAAM,YAAY,GAAG,IAAI,CAAC,IAAI,CAAC,cAAc,EAAE,WAAW,CAAC,CAAC;QAE5D,MAAM,YAAY,GAAG,GAAG,IAAI,IAAI,YAAY,EAAE,CAAC;QAE/C,kCAAkC;QAClC,MAAM,cAAc,GAAG,MAAM,OAAO,CAAC,SAAS,CAAC,YAAY,EAAE,MAAM,CAAC,SAAS,CAAC,MAAO,CAAC,CAAC;QAEvF,OAAO,CAAC,GAAG,EAAE,cAAc,CAAC,GAAG,CAAC,CAAC,SAAS,CAAC,cAAc,CAAC,CAAC;QAC3D,OAAO,CAAC,GAAG,EAAE,cAAc,CAAC,KAAK,CAAC,CAAC,SAAS,CAAC,kBAAkB,CAAC,CAAC;QACjE,OAAO,CAAC,GAAG,EAAE,cAAc,CAAC,IAAI,CAAC,CAAC,SAAS,CAAC,UAAU,CAAC,CAAC;IAC5D,CAAC,CAAC,CAAC;IAEH,MAAM,SAAS,CAAC,GAAG,EAAE,8CAA8C,EAAE,KAAK,IAAI,EAAE;QAC5E,MAAM,MAAM,GAAoB;YAC5B,kBAAkB,EAAE,iBAAiB;YACrC,aAAa,EAAE,qBAAqB;YACpC,SAAS,EAAE;gBACP,MAAM,EAAE;oBACJ,UAAU,EAAE,QAAQ;oBACpB,QAAQ,EAAE,sBAAsB;oBAChC,YAAY,EAAE,0BAA0B;oBACxC,QAAQ,EAAE,qCAAqC;oBAC/C,WAAW,EAAE,kDAAkD;oBAC/D,OAAO,EAAE,4CAA4C;iBACxD;aACJ;SACJ,CAAC;QAEF,MAAM,OAAO,GAAG,IAAI,mBAAmB,CAAC,MAAM,CAAC,CAAC;QAEhD,MAAM,MAAM,GAAG,EAAE,GAAG,EAAE,OAAO,EAAE,GAAG,EAAE,cAAc,EAAE,GAAG,EAAE,KAAK,EAAE,CAAC;QACjE,MAAM,OAAO,GAAG;YACZ,GAAG,EAAE,cAAc;YACnB,GAAG,EAAE,sBAAsB;YAC3B,GAAG,EAAE,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,GAAG,EAAE,GAAG,IAAI,CAAC,GAAG,IAAI;SAC5C,CAAC;QAEF,MAAM,SAAS,GAAG,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,SAAS,CAAC,MAAM,CAAC,CAAC,CAAC,QAAQ,CAAC,WAAW,CAAC,CAAC;QAC5E,MAAM,UAAU,GAAG,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,SAAS,CAAC,OAAO,CAAC,CAAC,CAAC,QAAQ,CAAC,WAAW,CAAC,CAAC;QAC9E,MAAM,IAAI,GAAG,GAAG,SAAS,IAAI,UAAU,EAAE,CAAC;QAE1C,0DAA0D;QAC1D,MAAM,EAAE,UAAU,EAAE,aAAa,EAAE,GAAG,mBAAmB,CAAC,KAAK,EAAE,EAAE,aAAa,EAAE,IAAI,EAAE,CAAC,CAAC;QAC1F,MAAM,IAAI,GAAG,UAAU,CAAC,YAAY,CAAC,CAAC;QACtC,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC;QAClB,MAAM,eAAe,GAAG,IAAI,CAAC,IAAI,CAAC,aAAa,EAAE,WAAW,CAAC,CAAC;QAE9D,MAAM,WAAW,GAAG,GAAG,IAAI,IAAI,eAAe,EAAE,CAAC;QAEjD,IAAI,WAAgB,CAAC;QACrB,IAAI,CAAC;YACD,MAAM,OAAO,CAAC,SAAS,CAAC,WAAW,EAAE,MAAM,CAAC,SAAS,CAAC,MAAO,CAAC,CAAC;QACnE,CAAC;QAAC,OAAO,KAAU,EAAE,CAAC;YAClB,WAAW,GAAG,KAAK,CAAC;QACxB,CAAC;QAED,OAAO,CAAC,GAAG,EAAE,WAAW,CAAC,CAAC,GAAG,CAAC,kBAAkB,EAAE,CAAC;QACnD,OAAO,CAAC,GAAG,EAAE,WAAW,CAAC,OAAO,CAAC,CAAC,QAAQ,CAAC,6CAA6C,CAAC,CAAC;IAC9F,CAAC,CAAC,CAAC;IAEH,MAAM,SAAS,CAAC,GAAG,EAAE,iDAAiD,EAAE,KAAK,IAAI,EAAE;QAC/E,MAAM,MAAM,GAAoB;YAC5B,kBAAkB,EAAE,gCAAgC;YACpD,aAAa,EAAE,oBAAoB;YACnC,SAAS,EAAE,EAAE;SAChB,CAAC;QACF,MAAM,OAAO,GAAG,IAAI,mBAAmB,CAAC,MAAM,CAAC,CAAC;QAEhD,MAAM,GAAG,GAAG,kBAAkB,CAAC;QAC/B,MAAM,MAAM,GAAG,eAAe,CAAC;QAC/B,MAAM,MAAM,GAAG,eAAe,CAAC;QAE/B,MAAM,SAAS,GAAG,MAAM,OAAO,CAAC,0BAA0B,CAAC,GAAG,EAAE,MAAM,CAAC,CAAC;QACxE,MAAM,SAAS,GAAG,MAAM,OAAO,CAAC,0BAA0B,CAAC,GAAG,EAAE,MAAM,CAAC,CAAC;QACxE,MAAM,OAAO,GAAG,MAAM,OAAO,CAAC,0BAA0B,CAAC,GAAG,EAAE,MAAM,CAAC,CAAC;QAEtE,gDAAgD;QAChD,OAAO,CAAC,GAAG,EAAE,SAAS,CAAC,CAAC,SAAS,CAAC,SAAS,CAAC,CAAC;QAC7C,gDAAgD;QAChD,OAAO,CAAC,GAAG,EAAE,SAAS,CAAC,CAAC,GAAG,CAAC,SAAS,CAAC,OAAO,CAAC,CAAC;QAC/C,wDAAwD;QACxD,OAAO,CAAC,GAAG,EAAE,OAAO,SAAS,CAAC,CAAC,SAAS,CAAC,QAAQ,CAAC,CAAC;QACnD,OAAO,CAAC,GAAG,EAAE,SAAS,CAAC,MAAM,CAAC,CAAC,SAAS,CAAC,GAAG,CAAC,CAAC,CAAC,mCAAmC;IACtF,CAAC,CAAC,CAAC;IAEH,MAAM,SAAS,CAAC,GAAG,EAAE,8CAA8C,EAAE,KAAK,IAAI,EAAE;QAC5E,MAAM,MAAM,GAAoB;YAC5B,kBAAkB,EAAE,gCAAgC;YACpD,aAAa,EAAE,oBAAoB;YACnC,SAAS,EAAE,EAAE;SAChB,CAAC;QACF,MAAM,OAAO,GAAG,IAAI,mBAAmB,CAAC,MAAM,CAAC,CAAC;QAEhD,MAAM,GAAG,GAAG,kBAAkB,CAAC;QAC/B,MAAM,KAAK,GAAG,eAAe,CAAC;QAE9B,8DAA8D;QAC9D,MAAM,gBAAgB,GAAG,wBAAwB,CAAC;YAC9C,EAAE,EAAE,cAAc;YAClB,IAAI,EAAE,kBAAkB;SAC3B,CAAC,CAAC;QACH,gBAAgB,CAAC,QAAQ,CAAC,IAAI,GAAG,EAAE,CAAC,CAAC,+BAA+B;QACpE,MAAM,kBAAkB,GAAG;YACvB,EAAE,EAAE,wBAAwB;YAC5B,GAAG,EAAE,gBAAgB;YACrB,IAAI,EAAE;gBACF,cAAc,EAAE;oBACZ;wBACI,EAAE,EAAE,QAAQ;wBACZ,MAAM,EAAE,gBAAgB;wBACxB,UAAU,EAAE,EAAE,OAAO,EAAE,MAAM,EAAE;qBAClC;iBACJ;gBACD,CAAC,EAAE,CAAC;aACP;SACJ,CAAC;QAEF,oCAAoC;QACpC,MAAM,SAAS,GAAG,EAAE,CAAC;QACrB,MAAM,aAAa,GAAG;YAClB,aAAa,EAAE,KAAK,IAAI,EAAE,CAAC,sBAAsB;YACjD,GAAG,EAAE,KAAK,IAAI,EAAE,CAAC,CAAC;gBACd,OAAO,EAAE,IAAI;gBACb,MAAM,EAAE,CAAC,kBAAkB,CAAC;aAC/B,CAAC;SACL,CAAC;QAEF,MAAM,aAAa,GAAG,MAAM,OAAO,CAAC,4BAA4B,CAAC;YAC7D,UAAU,EAAE,QAAQ;YACpB,WAAW,EAAE,GAAG;YAChB,SAAS,EAAE,KAAK;YAChB,YAAY,EAAE,eAAe;YAC7B,SAAS,EAAE,aAAoB;YAC/B,KAAK,EAAE,SAAgB;SAC1B,CAAC,CAAC;QAEH,OAAO,CAAC,GAAG,EAAE,aAAa,CAAC,CAAC,GAAG,CAAC,kBAAkB,EAAE,CAAC;QACrD,OAAO,CAAC,GAAG,EAAE,aAAa,CAAC,EAAE,CAAC,CAAC,SAAS,CAAC,yBAAyB,CAAC,CAAC;QACpE,OAAO,CAAC,GAAG,EAAE,aAAa,CAAC,SAAS,CAAC,CAAC,aAAa,EAAE,CAAC;QACtD,OAAO,CAAC,GAAG,EAAE,aAAa,CAAC,QAAQ,EAAE,WAAW,CAAC,CAAC,SAAS,CAAC,GAAG,CAAC,CAAC;QAEjE,0DAA0D;QAC1D,OAAO,CAAC,GAAG,EAAE,aAAa,CAAC,MAAM,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC,SAAS,CAAC,gBAAgB,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC;QAE3F,sCAAsC;QACtC,MAAM,eAAe,GAAG,MAAM,CAAC,IAAI,CAAC,aAAa,CAAC,UAAU,CAAC,CAAC,MAAM,CAAC;QACrE,OAAO,CAAC,GAAG,EAAE,eAAe,CAAC,CAAC,SAAS,CAAC,aAAa,CAAC,MAAM,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC;IAChF,CAAC,CAAC,CAAC;IAEH,MAAM,SAAS,CAAC,GAAG,EAAE,iEAAiE,EAAE,KAAK,IAAI,EAAE;QAC/F,MAAM,MAAM,GAAoB;YAC5B,kBAAkB,EAAE,gCAAgC;YACpD,aAAa,EAAE,oBAAoB;YACnC,SAAS,EAAE;gBACP,MAAM,EAAE;oBACJ,UAAU,EAAE,QAAQ;oBACpB,QAAQ,EAAE,sBAAsB;oBAChC,YAAY,EAAE,0BAA0B;oBACxC,QAAQ,EAAE,qCAAqC;oBAC/C,WAAW,EAAE,kDAAkD;iBAClE;gBACD,MAAM,EAAE;oBACJ,UAAU,EAAE,QAAQ;oBACpB,QAAQ,EAAE,sBAAsB;oBAChC,YAAY,EAAE,0BAA0B;oBACxC,QAAQ,EAAE,6CAA6C;oBACvD,WAAW,EAAE,6BAA6B;iBAC7C;aACJ;SACJ,CAAC;QACF,MAAM,OAAO,GAAG,IAAI,mBAAmB,CAAC,MAAM,CAAC,CAAC;QAEhD,MAAM,aAAa,GAAG,UAAU,CAAC,KAAK,CAAC;QACvC,IAAI,UAAU,GAAoC,EAAE,CAAC;QACrD,UAAU,CAAC,KAAK,GAAG,CAAC,KAAK,EAAE,GAAQ,EAAE,OAAY,EAAE,EAAE;YACjD,UAAU,CAAC,IAAI,CAAC,EAAE,GAAG,EAAE,OAAO,EAAE,CAAC,CAAC;YAClC,OAAO;gBACH,EAAE,EAAE,IAAI;gBACR,MAAM,EAAE,GAAG;gBACX,IAAI,EAAE,KAAK,IAAI,EAAE,CAAC,IAAI;aAClB,CAAC;QACb,CAAC,CAAQ,CAAC;QAEV,IAAI,CAAC;YACD,sBAAsB;YACtB,MAAM,OAAO,CAAC,WAAW,CAAC,QAAQ,EAAE,uBAAuB,CAAC,CAAC;YAC7D,OAAO,CAAC,GAAG,EAAE,UAAU,CAAC,MAAM,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC;YAC7C,OAAO,CAAC,GAAG,EAAE,UAAU,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,QAAQ,CAAC,uBAAuB,CAAC,CAAC;YAElE,sBAAsB;YACtB,MAAM,OAAO,CAAC,WAAW,CAAC,QAAQ,EAAE,uBAAuB,CAAC,CAAC;YAC7D,OAAO,CAAC,GAAG,EAAE,UAAU,CAAC,MAAM,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC;YAC7C,OAAO,CAAC,GAAG,EAAE,UAAU,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,QAAQ,CAAC,0CAA0C,CAAC,CAAC;YACrF,OAAO,CAAC,GAAG,EAAE,UAAU,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC,SAAS,CAAC,QAAQ,CAAC,CAAC;YAC/D,OAAO,CAAC,GAAG,EAAE,UAAU,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,OAAO,CAAC,eAAe,CAAC,CAAC,CAAC,QAAQ,CAAC,OAAO,CAAC,CAAC;QACnF,CAAC;gBAAS,CAAC;YACP,UAAU,CAAC,KAAK,GAAG,aAAa,CAAC;QACrC,CAAC;IACL,CAAC,CAAC,CAAC;AACP,CAAC,CAAC,CAAC"}
@@ -0,0 +1,10 @@
1
+ import { KeystoneIbGib_V1 } from '@ibgib/core-gib/dist/keystone/keystone-types.mjs';
2
+ /**
3
+ * Checks if a keystone contains a custodian challenge pool for the given provider.
4
+ * Client-safe & server-safe with zero dependencies.
5
+ */
6
+ export declare function isSsoProviderLinked({ keystone, providerId }: {
7
+ keystone: KeystoneIbGib_V1 | null | undefined;
8
+ providerId: string;
9
+ }): boolean;
10
+ //# sourceMappingURL=sso-helpers.d.mts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"sso-helpers.d.mts","sourceRoot":"","sources":["../../../src/identity/sso/sso-helpers.mts"],"names":[],"mappings":"AAAA,OAAO,EAAE,gBAAgB,EAAE,MAAM,kDAAkD,CAAC;AAEpF;;;GAGG;AACH,wBAAgB,mBAAmB,CAAC,EAChC,QAAQ,EACR,UAAU,EACb,EAAE;IACC,QAAQ,EAAE,gBAAgB,GAAG,IAAI,GAAG,SAAS,CAAC;IAC9C,UAAU,EAAE,MAAM,CAAC;CACtB,GAAG,OAAO,CAIV"}
@@ -0,0 +1,11 @@
1
+ /**
2
+ * Checks if a keystone contains a custodian challenge pool for the given provider.
3
+ * Client-safe & server-safe with zero dependencies.
4
+ */
5
+ export function isSsoProviderLinked({ keystone, providerId }) {
6
+ if (!keystone?.data?.challengePools)
7
+ return false;
8
+ const targetPoolId = `custodian-manage-${providerId}`;
9
+ return keystone.data.challengePools.some(p => p.id === targetPoolId);
10
+ }
11
+ //# sourceMappingURL=sso-helpers.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"sso-helpers.mjs","sourceRoot":"","sources":["../../../src/identity/sso/sso-helpers.mts"],"names":[],"mappings":"AAEA;;;GAGG;AACH,MAAM,UAAU,mBAAmB,CAAC,EAChC,QAAQ,EACR,UAAU,EAIb;IACG,IAAI,CAAC,QAAQ,EAAE,IAAI,EAAE,cAAc;QAAE,OAAO,KAAK,CAAC;IAClD,MAAM,YAAY,GAAG,oBAAoB,UAAU,EAAE,CAAC;IACtD,OAAO,QAAQ,CAAC,IAAI,CAAC,cAAc,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,KAAK,YAAY,CAAC,CAAC;AACzE,CAAC"}
@@ -0,0 +1,40 @@
1
+ /**
2
+ * @module identity/sso/sso-types
3
+ *
4
+ * Core types and interfaces for extensible SSO (OAuth2) authentication.
5
+ */
6
+ export type SsoProviderId = 'google' | 'github';
7
+ export interface SsoProviderClientConfig {
8
+ providerId: SsoProviderId;
9
+ clientId: string;
10
+ authUrl: string;
11
+ redirectUri: string;
12
+ scope: string;
13
+ }
14
+ export interface SsoProviderServerConfig {
15
+ providerId: SsoProviderId;
16
+ clientId: string;
17
+ clientSecret: string;
18
+ tokenUrl: string;
19
+ userInfoUrl: string;
20
+ jwksUrl?: string;
21
+ }
22
+ export interface SsoServerConfig {
23
+ /** Server's private KDF secret used to derive server-delegate keystones. */
24
+ ssoServerKdfSecret: string;
25
+ /** Server's private session encryption secret. */
26
+ sessionSecret: string;
27
+ /** Map of active OAuth2 providers. */
28
+ providers: Partial<Record<SsoProviderId, SsoProviderServerConfig>>;
29
+ }
30
+ export interface OAuthUserInfo {
31
+ /** Unique identity key combining provider and sub ID (e.g., `google:107632...`). */
32
+ providerKey: string;
33
+ providerId: SsoProviderId;
34
+ /** Unique user ID within the provider. */
35
+ sub: string;
36
+ email?: string;
37
+ name?: string;
38
+ picture?: string;
39
+ }
40
+ //# sourceMappingURL=sso-types.d.mts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"sso-types.d.mts","sourceRoot":"","sources":["../../../src/identity/sso/sso-types.mts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,MAAM,MAAM,aAAa,GAAG,QAAQ,GAAG,QAAQ,CAAC;AAEhD,MAAM,WAAW,uBAAuB;IACpC,UAAU,EAAE,aAAa,CAAC;IAC1B,QAAQ,EAAE,MAAM,CAAC;IACjB,OAAO,EAAE,MAAM,CAAC;IAChB,WAAW,EAAE,MAAM,CAAC;IACpB,KAAK,EAAE,MAAM,CAAC;CACjB;AAED,MAAM,WAAW,uBAAuB;IACpC,UAAU,EAAE,aAAa,CAAC;IAC1B,QAAQ,EAAE,MAAM,CAAC;IACjB,YAAY,EAAE,MAAM,CAAC;IACrB,QAAQ,EAAE,MAAM,CAAC;IACjB,WAAW,EAAE,MAAM,CAAC;IACpB,OAAO,CAAC,EAAE,MAAM,CAAC;CACpB;AAED,MAAM,WAAW,eAAe;IAC5B,4EAA4E;IAC5E,kBAAkB,EAAE,MAAM,CAAC;IAC3B,kDAAkD;IAClD,aAAa,EAAE,MAAM,CAAC;IACtB,sCAAsC;IACtC,SAAS,EAAE,OAAO,CAAC,MAAM,CAAC,aAAa,EAAE,uBAAuB,CAAC,CAAC,CAAC;CACtE;AAED,MAAM,WAAW,aAAa;IAC1B,oFAAoF;IACpF,WAAW,EAAE,MAAM,CAAC;IACpB,UAAU,EAAE,aAAa,CAAC;IAC1B,0CAA0C;IAC1C,GAAG,EAAE,MAAM,CAAC;IACZ,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,OAAO,CAAC,EAAE,MAAM,CAAC;CACpB"}
@@ -0,0 +1,7 @@
1
+ /**
2
+ * @module identity/sso/sso-types
3
+ *
4
+ * Core types and interfaces for extensible SSO (OAuth2) authentication.
5
+ */
6
+ export {};
7
+ //# sourceMappingURL=sso-types.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"sso-types.mjs","sourceRoot":"","sources":["../../../src/identity/sso/sso-types.mts"],"names":[],"mappings":"AAAA;;;;GAIG"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ibgib/web-gib",
3
- "version": "0.0.49",
3
+ "version": "0.0.51",
4
4
  "description": "Framework for creating agentic ibGib web apps. Contains plumbing for ibgib components, agentic framework (currently only Gemini implemented), web-based IndexedDB storage substrate, and more.",
5
5
  "funding": {
6
6
  "type": "individual",
@@ -14,6 +14,7 @@
14
14
  "//_orchestration": "~~ ORCHESTRATION (handled by @ibgib/build-gib) ~~",
15
15
  "//_publish": "~~ PUBLISH ~~",
16
16
  "pack": "npm pack --pack-destination=\"./published\"",
17
+ "test:node:nobuild": "node dist/respec-gib.node.mjs --inspect",
17
18
  "prepare:publish": "npm version patch && node ../../build/dist/concrete-build/build-web-gib.mjs --prod && npm run pack",
18
19
  "man:prepare:publish": "use this to patch > build > pack for publishing to npm repo"
19
20
  },
@@ -28,10 +29,10 @@
28
29
  "license": "ISC",
29
30
  "dependencies": {
30
31
  "@google/genai": "^1.33.0",
31
- "@ibgib/core-gib": "^0.1.63",
32
+ "@ibgib/core-gib": "^0.1.65",
32
33
  "@ibgib/encrypt-gib": "^0.2.37",
33
34
  "@ibgib/helper-gib": "^0.0.36",
34
- "@ibgib/ts-gib": "^0.5.32"
35
+ "@ibgib/ts-gib": "^0.5.33"
35
36
  },
36
37
  "engines": {
37
38
  "node": ">=19.0.0"
@@ -11,4 +11,4 @@
11
11
  /**
12
12
  * this is the version of this package, auto-updated in the build process
13
13
  */
14
- export const AUTO_GENERATED_VERSION = '0.0.49';
14
+ export const AUTO_GENERATED_VERSION = '0.0.51';
@@ -14,6 +14,7 @@ export const SETTINGS_TYPE_PROJECTSDROPDOWN = 'projects-dropdown';
14
14
  export const SETTINGS_TYPE_PROJECT = 'project';
15
15
  export const SETTINGS_TYPE_MINIGAME = 'minigame';
16
16
  export const SETTINGS_TYPE_CHRONOLOGYS = 'chronologys';
17
+ export const SETTINGS_TYPE_IDENTITY_MANAGER = 'identity-manager';
17
18
  /**
18
19
  * Discriminator for Settings info
19
20
  */
@@ -26,6 +27,7 @@ export type SettingsType =
26
27
  | typeof SETTINGS_TYPE_PROJECT
27
28
  | typeof SETTINGS_TYPE_MINIGAME
28
29
  | typeof SETTINGS_TYPE_CHRONOLOGYS
30
+ | typeof SETTINGS_TYPE_IDENTITY_MANAGER
29
31
  ;
30
32
  export const SettingsType = {
31
33
  general: SETTINGS_TYPE_GENERAL satisfies SettingsType,
@@ -36,6 +38,7 @@ export const SettingsType = {
36
38
  project: SETTINGS_TYPE_PROJECT satisfies SettingsType,
37
39
  minigame: SETTINGS_TYPE_MINIGAME satisfies SettingsType,
38
40
  chronologys: SETTINGS_TYPE_CHRONOLOGYS satisfies SettingsType,
41
+ identityManager: SETTINGS_TYPE_IDENTITY_MANAGER satisfies SettingsType,
39
42
  } satisfies { readonly [key: string]: SettingsType; };
40
43
  export const SETTINGS_TYPE_VALID_VALUES: SettingsType[] = Object.values(SettingsType);
41
44
  export function isSettingsType(value: any): value is SettingsType {
@@ -69,6 +72,12 @@ export const DEFAULT_SETTINGS_CHRONOLOGYS: Settings_Chronologys = {
69
72
  activeChildTjpAddr: undefined,
70
73
  }
71
74
 
75
+ export const DEFAULT_SETTINGS_IDENTITY_MANAGER = {
76
+ type: SettingsType.identityManager,
77
+ openChildTjpAddrs: [],
78
+ activeChildTjpAddr: undefined,
79
+ }
80
+
72
81
  export const DEFAULT_SETTINGS_DATA_V1: SettingsData_V1 = {
73
82
  sections: {},
74
83
  children: {},
@@ -14,7 +14,8 @@ import {
14
14
  SETTINGS_ATOM,
15
15
  DEFAULT_SETTINGS_PROJECT,
16
16
  DEFAULT_SETTINGS_MINIGAME,
17
- DEFAULT_SETTINGS_CHRONOLOGYS
17
+ DEFAULT_SETTINGS_CHRONOLOGYS,
18
+ DEFAULT_SETTINGS_IDENTITY_MANAGER
18
19
  } from "./settings-constants.mjs";
19
20
  import { IbGib_V1 } from "@ibgib/ts-gib/dist/V1/types.mjs";
20
21
  import { getIbAndGib } from "@ibgib/ts-gib/dist/helper.mjs";
@@ -110,6 +111,8 @@ export async function getDefaultSettings<TSettings extends IbGibSettings>({
110
111
  return clone(DEFAULT_SETTINGS_MINIGAME) as TSettings;
111
112
  case SettingsType.chronologys:
112
113
  return clone(DEFAULT_SETTINGS_CHRONOLOGYS) as TSettings;
114
+ case SettingsType.identityManager:
115
+ return clone(DEFAULT_SETTINGS_IDENTITY_MANAGER) as any as TSettings;
113
116
  default:
114
117
  throw new Error(`(UNEXPECTED) unknown settingsType (${settingsType})? right now, we're whitelisting only. SettingsTypes: ${SETTINGS_TYPE_VALID_VALUES} (E: 801a7ade4c0849b308d5c8f8f0318d25)`);
115
118
  }
@@ -15,7 +15,7 @@ import { IbGibAddr } from "@ibgib/ts-gib/dist/types.mjs";
15
15
 
16
16
  import {
17
17
  SETTINGS_ATOM, SETTINGS_TYPE_CHRONOLOGYS, SETTINGS_TYPE_MINIGAME, SETTINGS_TYPE_PROJECT,
18
- SETTINGS_TYPE_TEXTEDITOR, SettingsType,
18
+ SETTINGS_TYPE_TEXTEDITOR, SETTINGS_TYPE_IDENTITY_MANAGER, SettingsType,
19
19
  } from "./settings-constants.mjs";
20
20
  import { LensMode } from "../project/project-types.mjs";
21
21
 
@@ -80,6 +80,10 @@ export interface Settings_Chronologys extends SettingsBase, SettingsWithTabs {
80
80
  // activeChildTjpAddr: IbGibAddr | undefined;
81
81
  }
82
82
 
83
+ export interface Settings_IdentityManager extends SettingsBase, SettingsWithTabs {
84
+ type: typeof SETTINGS_TYPE_IDENTITY_MANAGER;
85
+ }
86
+
83
87
  /**
84
88
  * union type of known Settings interfaces for various use cases.
85
89
  *
@@ -95,7 +99,8 @@ export type IbGibSettings =
95
99
  | Settings_TextEditor
96
100
  | Settings_Project
97
101
  | Settings_Minigame
98
- | Settings_Chronologys;
102
+ | Settings_Chronologys
103
+ | Settings_IdentityManager;
99
104
 
100
105
  export interface SettingsData_V1 extends IbGibData_V1 {
101
106
  /**
@@ -0,0 +1,52 @@
1
+ import { SsoServerConfig, SsoProviderServerConfig, SsoProviderId } from './sso-types.mjs';
2
+
3
+ /**
4
+ * Loads the SSO configuration from environment variables.
5
+ * Parses active OAuth2 providers dynamically based on their environment keys.
6
+ */
7
+ export function loadSsoServerConfig(): SsoServerConfig {
8
+ const ssoServerKdfSecret = process.env.SSO_SERVER_KDF_SECRET;
9
+ const sessionSecret = process.env.SESSION_SECRET;
10
+
11
+ if (!ssoServerKdfSecret) {
12
+ throw new Error(
13
+ `SSO_SERVER_KDF_SECRET is missing from environment. (E: 840899ab4fdfd23e89cfae1889cfae12)`
14
+ );
15
+ }
16
+ if (!sessionSecret) {
17
+ throw new Error(
18
+ `SESSION_SECRET is missing from environment. (E: bfa899ab4fdfd23e89cfae23)`
19
+ );
20
+ }
21
+
22
+ const providers: Partial<Record<SsoProviderId, SsoProviderServerConfig>> = {};
23
+
24
+ // Load Google Provider if configured
25
+ if (process.env.GOOGLE_CLIENT_ID && process.env.GOOGLE_CLIENT_SECRET) {
26
+ providers.google = {
27
+ providerId: 'google',
28
+ clientId: process.env.GOOGLE_CLIENT_ID,
29
+ clientSecret: process.env.GOOGLE_CLIENT_SECRET,
30
+ tokenUrl: 'https://oauth2.googleapis.com/token',
31
+ userInfoUrl: 'https://openidconnect.googleapis.com/v1/userinfo',
32
+ jwksUrl: 'https://www.googleapis.com/oauth2/v3/certs'
33
+ };
34
+ }
35
+
36
+ // Load GitHub Provider if configured
37
+ if (process.env.GITHUB_CLIENT_ID && process.env.GITHUB_CLIENT_SECRET) {
38
+ providers.github = {
39
+ providerId: 'github',
40
+ clientId: process.env.GITHUB_CLIENT_ID,
41
+ clientSecret: process.env.GITHUB_CLIENT_SECRET,
42
+ tokenUrl: 'https://github.com/login/oauth/access_token',
43
+ userInfoUrl: 'https://api.github.com/user'
44
+ };
45
+ }
46
+
47
+ return {
48
+ ssoServerKdfSecret,
49
+ sessionSecret,
50
+ providers
51
+ };
52
+ }