@enterprisestandard/react 0.0.5-beta.20260115.3 → 0.0.5-beta.20260115.4
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/dist/index.d.ts +2573 -41
- package/dist/index.js +3732 -144
- package/dist/index.js.map +1 -0
- package/package.json +3 -1
- package/dist/group-store.d.ts +0 -164
- package/dist/group-store.d.ts.map +0 -1
- package/dist/group-store.js +0 -127
- package/dist/iam.d.ts +0 -206
- package/dist/iam.d.ts.map +0 -1
- package/dist/iam.js +0 -680
- package/dist/index.d.ts.map +0 -1
- package/dist/session-store.d.ts +0 -179
- package/dist/session-store.d.ts.map +0 -1
- package/dist/session-store.js +0 -105
- package/dist/sso-server.d.ts +0 -13
- package/dist/sso-server.d.ts.map +0 -1
- package/dist/sso-server.js +0 -46
- package/dist/sso.d.ts +0 -104
- package/dist/sso.d.ts.map +0 -1
- package/dist/sso.js +0 -820
- package/dist/tenant-server.d.ts +0 -8
- package/dist/tenant-server.d.ts.map +0 -1
- package/dist/tenant-server.js +0 -6
- package/dist/tenant.d.ts +0 -280
- package/dist/tenant.d.ts.map +0 -1
- package/dist/tenant.js +0 -324
- package/dist/types/base-user.d.ts +0 -27
- package/dist/types/base-user.d.ts.map +0 -1
- package/dist/types/base-user.js +0 -1
- package/dist/types/enterprise-user.d.ts +0 -158
- package/dist/types/enterprise-user.d.ts.map +0 -1
- package/dist/types/enterprise-user.js +0 -1
- package/dist/types/oidc-schema.d.ts +0 -86
- package/dist/types/oidc-schema.d.ts.map +0 -1
- package/dist/types/oidc-schema.js +0 -328
- package/dist/types/scim-schema.d.ts +0 -419
- package/dist/types/scim-schema.d.ts.map +0 -1
- package/dist/types/scim-schema.js +0 -519
- package/dist/types/standard-schema.d.ts +0 -56
- package/dist/types/standard-schema.d.ts.map +0 -1
- package/dist/types/standard-schema.js +0 -1
- package/dist/types/user.d.ts +0 -41
- package/dist/types/user.d.ts.map +0 -1
- package/dist/types/user.js +0 -1
- package/dist/types/workload-schema.d.ts +0 -106
- package/dist/types/workload-schema.d.ts.map +0 -1
- package/dist/types/workload-schema.js +0 -208
- package/dist/ui/sign-in-loading.d.ts +0 -5
- package/dist/ui/sign-in-loading.d.ts.map +0 -1
- package/dist/ui/sign-in-loading.js +0 -8
- package/dist/ui/signed-in.d.ts +0 -3
- package/dist/ui/signed-in.d.ts.map +0 -1
- package/dist/ui/signed-in.js +0 -8
- package/dist/ui/signed-out.d.ts +0 -3
- package/dist/ui/signed-out.d.ts.map +0 -1
- package/dist/ui/signed-out.js +0 -8
- package/dist/ui/sso-provider.d.ts +0 -35
- package/dist/ui/sso-provider.d.ts.map +0 -1
- package/dist/ui/sso-provider.js +0 -275
- package/dist/user-store.d.ts +0 -161
- package/dist/user-store.d.ts.map +0 -1
- package/dist/user-store.js +0 -114
- package/dist/utils.d.ts +0 -9
- package/dist/utils.d.ts.map +0 -1
- package/dist/utils.js +0 -23
- package/dist/vault.d.ts +0 -18
- package/dist/vault.d.ts.map +0 -1
- package/dist/vault.js +0 -22
- package/dist/workload-server.d.ts +0 -127
- package/dist/workload-server.d.ts.map +0 -1
- package/dist/workload-server.js +0 -167
- package/dist/workload-token-store.d.ts +0 -187
- package/dist/workload-token-store.d.ts.map +0 -1
- package/dist/workload-token-store.js +0 -95
- package/dist/workload.d.ts +0 -227
- package/dist/workload.d.ts.map +0 -1
- package/dist/workload.js +0 -691
package/dist/index.d.ts
CHANGED
|
@@ -1,8 +1,2573 @@
|
|
|
1
|
-
import
|
|
2
|
-
import {
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
1
|
+
import * as react_jsx_runtime from 'react/jsx-runtime';
|
|
2
|
+
import { PropsWithChildren, ReactNode } from 'react';
|
|
3
|
+
|
|
4
|
+
/** The Standard Schema interface. @see https://standardschema.dev/ */
|
|
5
|
+
interface StandardSchemaV1<Input = unknown, Output = Input> {
|
|
6
|
+
/** The Standard Schema properties. */
|
|
7
|
+
readonly '~standard': StandardSchemaV1.Props<Input, Output>;
|
|
8
|
+
}
|
|
9
|
+
declare namespace StandardSchemaV1 {
|
|
10
|
+
/** The Standard Schema properties interface. */
|
|
11
|
+
interface Props<Input = unknown, Output = Input> {
|
|
12
|
+
/** The version number of the standard. */
|
|
13
|
+
readonly version: 1;
|
|
14
|
+
/** The vendor name of the schema library. */
|
|
15
|
+
readonly vendor: string;
|
|
16
|
+
/** Validates unknown input values. */
|
|
17
|
+
readonly validate: (value: unknown) => Result<Output> | Promise<Result<Output>>;
|
|
18
|
+
/** Inferred types associated with the schema. */
|
|
19
|
+
readonly types?: Types<Input, Output> | undefined;
|
|
20
|
+
}
|
|
21
|
+
/** The result interface of the validate function. */
|
|
22
|
+
type Result<Output> = SuccessResult<Output> | FailureResult;
|
|
23
|
+
/** The result interface if validation succeeds. */
|
|
24
|
+
interface SuccessResult<Output> {
|
|
25
|
+
/** The typed output value. */
|
|
26
|
+
readonly value: Output;
|
|
27
|
+
/** The non-existent issues. */
|
|
28
|
+
readonly issues?: undefined;
|
|
29
|
+
}
|
|
30
|
+
/** The result interface if validation fails. */
|
|
31
|
+
interface FailureResult {
|
|
32
|
+
/** The issues of failed validation. */
|
|
33
|
+
readonly issues: ReadonlyArray<Issue>;
|
|
34
|
+
}
|
|
35
|
+
/** The issue interface of the failure output. */
|
|
36
|
+
interface Issue {
|
|
37
|
+
/** The error message of the issue. */
|
|
38
|
+
readonly message: string;
|
|
39
|
+
/** The path of the issue, if any. */
|
|
40
|
+
readonly path?: ReadonlyArray<PropertyKey | PathSegment> | undefined;
|
|
41
|
+
}
|
|
42
|
+
/** The path segment interface of the issue. */
|
|
43
|
+
interface PathSegment {
|
|
44
|
+
/** The key representing a path segment. */
|
|
45
|
+
readonly key: PropertyKey;
|
|
46
|
+
}
|
|
47
|
+
/** The Standard Schema types interface. */
|
|
48
|
+
interface Types<Input = unknown, Output = Input> {
|
|
49
|
+
/** The input type of the schema. */
|
|
50
|
+
readonly input: Input;
|
|
51
|
+
/** The output type of the schema. */
|
|
52
|
+
readonly output: Output;
|
|
53
|
+
}
|
|
54
|
+
/** Infers the input type of a Standard Schema. */
|
|
55
|
+
type InferInput<Schema extends StandardSchemaV1> = NonNullable<Schema['~standard']['types']>['input'];
|
|
56
|
+
/** Infers the output type of a Standard Schema. */
|
|
57
|
+
type InferOutput<Schema extends StandardSchemaV1> = NonNullable<Schema['~standard']['types']>['output'];
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
/**
|
|
61
|
+
* SCIM 2.0 User Resource
|
|
62
|
+
* @see https://datatracker.ietf.org/doc/html/rfc7643#section-4.1
|
|
63
|
+
*/
|
|
64
|
+
/**
|
|
65
|
+
* SCIM Name sub-attribute
|
|
66
|
+
*/
|
|
67
|
+
interface Name {
|
|
68
|
+
/**
|
|
69
|
+
* The full name, including all middle names, titles, and suffixes as appropriate
|
|
70
|
+
*/
|
|
71
|
+
formatted?: string;
|
|
72
|
+
/**
|
|
73
|
+
* The family name of the User, or last name
|
|
74
|
+
*/
|
|
75
|
+
familyName?: string;
|
|
76
|
+
/**
|
|
77
|
+
* The given name of the User, or first name
|
|
78
|
+
*/
|
|
79
|
+
givenName?: string;
|
|
80
|
+
/**
|
|
81
|
+
* The middle name(s) of the User
|
|
82
|
+
*/
|
|
83
|
+
middleName?: string;
|
|
84
|
+
/**
|
|
85
|
+
* The honorific prefix(es) of the User, or title
|
|
86
|
+
*/
|
|
87
|
+
honorificPrefix?: string;
|
|
88
|
+
/**
|
|
89
|
+
* The honorific suffix(es) of the User, or suffix
|
|
90
|
+
*/
|
|
91
|
+
honorificSuffix?: string;
|
|
92
|
+
}
|
|
93
|
+
/**
|
|
94
|
+
* SCIM Email sub-attribute
|
|
95
|
+
*/
|
|
96
|
+
interface Email {
|
|
97
|
+
/**
|
|
98
|
+
* The email address value
|
|
99
|
+
*/
|
|
100
|
+
value: string;
|
|
101
|
+
/**
|
|
102
|
+
* A human-readable name, primarily used for display purposes
|
|
103
|
+
*/
|
|
104
|
+
display?: string;
|
|
105
|
+
/**
|
|
106
|
+
* A label indicating the attribute's function (e.g., "work" or "home")
|
|
107
|
+
*/
|
|
108
|
+
type?: string;
|
|
109
|
+
/**
|
|
110
|
+
* A Boolean value indicating the 'primary' or preferred attribute value
|
|
111
|
+
*/
|
|
112
|
+
primary?: boolean;
|
|
113
|
+
}
|
|
114
|
+
/**
|
|
115
|
+
* SCIM Phone Number sub-attribute
|
|
116
|
+
*/
|
|
117
|
+
interface PhoneNumber {
|
|
118
|
+
/**
|
|
119
|
+
* The phone number value
|
|
120
|
+
*/
|
|
121
|
+
value: string;
|
|
122
|
+
/**
|
|
123
|
+
* A human-readable name, primarily used for display purposes
|
|
124
|
+
*/
|
|
125
|
+
display?: string;
|
|
126
|
+
/**
|
|
127
|
+
* A label indicating the attribute's function (e.g., "work", "home", "mobile")
|
|
128
|
+
*/
|
|
129
|
+
type?: string;
|
|
130
|
+
/**
|
|
131
|
+
* A Boolean value indicating the 'primary' or preferred attribute value
|
|
132
|
+
*/
|
|
133
|
+
primary?: boolean;
|
|
134
|
+
}
|
|
135
|
+
/**
|
|
136
|
+
* SCIM Address sub-attribute
|
|
137
|
+
*/
|
|
138
|
+
interface Address {
|
|
139
|
+
/**
|
|
140
|
+
* The full mailing address, formatted for display
|
|
141
|
+
*/
|
|
142
|
+
formatted?: string;
|
|
143
|
+
/**
|
|
144
|
+
* The full street address component
|
|
145
|
+
*/
|
|
146
|
+
streetAddress?: string;
|
|
147
|
+
/**
|
|
148
|
+
* The city or locality component
|
|
149
|
+
*/
|
|
150
|
+
locality?: string;
|
|
151
|
+
/**
|
|
152
|
+
* The state or region component
|
|
153
|
+
*/
|
|
154
|
+
region?: string;
|
|
155
|
+
/**
|
|
156
|
+
* The zip code or postal code component
|
|
157
|
+
*/
|
|
158
|
+
postalCode?: string;
|
|
159
|
+
/**
|
|
160
|
+
* The country name component
|
|
161
|
+
*/
|
|
162
|
+
country?: string;
|
|
163
|
+
/**
|
|
164
|
+
* A label indicating the attribute's function (e.g., "work" or "home")
|
|
165
|
+
*/
|
|
166
|
+
type?: string;
|
|
167
|
+
/**
|
|
168
|
+
* A Boolean value indicating the 'primary' or preferred attribute value
|
|
169
|
+
*/
|
|
170
|
+
primary?: boolean;
|
|
171
|
+
}
|
|
172
|
+
/**
|
|
173
|
+
* SCIM Group reference (used within User resources)
|
|
174
|
+
*/
|
|
175
|
+
interface Group {
|
|
176
|
+
/**
|
|
177
|
+
* The identifier of the User's group
|
|
178
|
+
*/
|
|
179
|
+
value: string;
|
|
180
|
+
/**
|
|
181
|
+
* The URI of the corresponding 'Group' resource
|
|
182
|
+
*/
|
|
183
|
+
$ref?: string;
|
|
184
|
+
/**
|
|
185
|
+
* A human-readable name, primarily used for display purposes
|
|
186
|
+
*/
|
|
187
|
+
display?: string;
|
|
188
|
+
/**
|
|
189
|
+
* A label indicating the attribute's function (e.g., "direct" or "indirect")
|
|
190
|
+
*/
|
|
191
|
+
type?: string;
|
|
192
|
+
}
|
|
193
|
+
/**
|
|
194
|
+
* SCIM Group Member reference
|
|
195
|
+
*/
|
|
196
|
+
interface GroupMember {
|
|
197
|
+
/**
|
|
198
|
+
* The identifier of the member (User or Group)
|
|
199
|
+
*/
|
|
200
|
+
value: string;
|
|
201
|
+
/**
|
|
202
|
+
* The URI of the corresponding member resource
|
|
203
|
+
*/
|
|
204
|
+
$ref?: string;
|
|
205
|
+
/**
|
|
206
|
+
* A human-readable name of the member
|
|
207
|
+
*/
|
|
208
|
+
display?: string;
|
|
209
|
+
/**
|
|
210
|
+
* The type of the member (e.g., "User" or "Group")
|
|
211
|
+
*/
|
|
212
|
+
type?: 'User' | 'Group';
|
|
213
|
+
}
|
|
214
|
+
/**
|
|
215
|
+
* SCIM 2.0 Group Resource
|
|
216
|
+
* @see https://datatracker.ietf.org/doc/html/rfc7643#section-4.2
|
|
217
|
+
*/
|
|
218
|
+
interface GroupResource {
|
|
219
|
+
/**
|
|
220
|
+
* REQUIRED. The schemas attribute
|
|
221
|
+
*/
|
|
222
|
+
schemas?: string[];
|
|
223
|
+
/**
|
|
224
|
+
* Unique identifier for the Group, assigned by the service provider
|
|
225
|
+
*/
|
|
226
|
+
id?: string;
|
|
227
|
+
/**
|
|
228
|
+
* External identifier from the provisioning client
|
|
229
|
+
*/
|
|
230
|
+
externalId?: string;
|
|
231
|
+
/**
|
|
232
|
+
* Resource metadata
|
|
233
|
+
*/
|
|
234
|
+
meta?: {
|
|
235
|
+
resourceType?: string;
|
|
236
|
+
created?: string;
|
|
237
|
+
lastModified?: string;
|
|
238
|
+
location?: string;
|
|
239
|
+
version?: string;
|
|
240
|
+
};
|
|
241
|
+
/**
|
|
242
|
+
* REQUIRED. A human-readable name for the Group
|
|
243
|
+
*/
|
|
244
|
+
displayName: string;
|
|
245
|
+
/**
|
|
246
|
+
* A list of members of the Group
|
|
247
|
+
*/
|
|
248
|
+
members?: GroupMember[];
|
|
249
|
+
}
|
|
250
|
+
/**
|
|
251
|
+
* SCIM Role
|
|
252
|
+
*/
|
|
253
|
+
interface Role {
|
|
254
|
+
/**
|
|
255
|
+
* The value of the role
|
|
256
|
+
*/
|
|
257
|
+
value: string;
|
|
258
|
+
/**
|
|
259
|
+
* A human-readable name, primarily used for display purposes
|
|
260
|
+
*/
|
|
261
|
+
display?: string;
|
|
262
|
+
/**
|
|
263
|
+
* A label indicating the attribute's function
|
|
264
|
+
*/
|
|
265
|
+
type?: string;
|
|
266
|
+
/**
|
|
267
|
+
* A Boolean value indicating the 'primary' or preferred attribute value
|
|
268
|
+
*/
|
|
269
|
+
primary?: boolean;
|
|
270
|
+
}
|
|
271
|
+
/**
|
|
272
|
+
* SCIM X509 Certificate
|
|
273
|
+
*/
|
|
274
|
+
interface X509Certificate {
|
|
275
|
+
/**
|
|
276
|
+
* The value of the X.509 certificate
|
|
277
|
+
*/
|
|
278
|
+
value: string;
|
|
279
|
+
/**
|
|
280
|
+
* A human-readable name, primarily used for display purposes
|
|
281
|
+
*/
|
|
282
|
+
display?: string;
|
|
283
|
+
/**
|
|
284
|
+
* A label indicating the attribute's function
|
|
285
|
+
*/
|
|
286
|
+
type?: string;
|
|
287
|
+
/**
|
|
288
|
+
* A Boolean value indicating the 'primary' or preferred attribute value
|
|
289
|
+
*/
|
|
290
|
+
primary?: boolean;
|
|
291
|
+
}
|
|
292
|
+
/**
|
|
293
|
+
* SCIM Enterprise User Extension
|
|
294
|
+
* @see https://datatracker.ietf.org/doc/html/rfc7643#section-4.3
|
|
295
|
+
*/
|
|
296
|
+
interface EnterpriseExtension {
|
|
297
|
+
/**
|
|
298
|
+
* Numeric or alphanumeric identifier assigned to a person
|
|
299
|
+
*/
|
|
300
|
+
employeeNumber?: string;
|
|
301
|
+
/**
|
|
302
|
+
* Identifies the name of a cost center
|
|
303
|
+
*/
|
|
304
|
+
costCenter?: string;
|
|
305
|
+
/**
|
|
306
|
+
* Identifies the name of an organization
|
|
307
|
+
*/
|
|
308
|
+
organization?: string;
|
|
309
|
+
/**
|
|
310
|
+
* Identifies the name of a division
|
|
311
|
+
*/
|
|
312
|
+
division?: string;
|
|
313
|
+
/**
|
|
314
|
+
* Identifies the name of a department
|
|
315
|
+
*/
|
|
316
|
+
department?: string;
|
|
317
|
+
/**
|
|
318
|
+
* The user's manager
|
|
319
|
+
*/
|
|
320
|
+
manager?: {
|
|
321
|
+
/**
|
|
322
|
+
* The "id" of the SCIM resource representing the User's manager
|
|
323
|
+
*/
|
|
324
|
+
value?: string;
|
|
325
|
+
/**
|
|
326
|
+
* The URI of the SCIM resource representing the User's manager
|
|
327
|
+
*/
|
|
328
|
+
$ref?: string;
|
|
329
|
+
/**
|
|
330
|
+
* The displayName of the User's manager
|
|
331
|
+
*/
|
|
332
|
+
displayName?: string;
|
|
333
|
+
};
|
|
334
|
+
}
|
|
335
|
+
/**
|
|
336
|
+
* SCIM User Resource
|
|
337
|
+
*/
|
|
338
|
+
interface User$1 {
|
|
339
|
+
/**
|
|
340
|
+
* REQUIRED. Unique identifier for the User, typically from the provider
|
|
341
|
+
*/
|
|
342
|
+
id?: string;
|
|
343
|
+
/**
|
|
344
|
+
* REQUIRED. A unique identifier for a SCIM resource as defined by the service provider
|
|
345
|
+
*/
|
|
346
|
+
externalId?: string;
|
|
347
|
+
/**
|
|
348
|
+
* Resource metadata
|
|
349
|
+
*/
|
|
350
|
+
meta?: {
|
|
351
|
+
resourceType?: string;
|
|
352
|
+
created?: string;
|
|
353
|
+
lastModified?: string;
|
|
354
|
+
location?: string;
|
|
355
|
+
version?: string;
|
|
356
|
+
};
|
|
357
|
+
/**
|
|
358
|
+
* REQUIRED. Unique identifier for the User, typically used for login
|
|
359
|
+
*/
|
|
360
|
+
userName: string;
|
|
361
|
+
/**
|
|
362
|
+
* The components of the user's name
|
|
363
|
+
*/
|
|
364
|
+
name?: Name;
|
|
365
|
+
/**
|
|
366
|
+
* The name of the User, suitable for display to end-users
|
|
367
|
+
*/
|
|
368
|
+
displayName?: string;
|
|
369
|
+
/**
|
|
370
|
+
* The casual way to address the user
|
|
371
|
+
*/
|
|
372
|
+
nickName?: string;
|
|
373
|
+
/**
|
|
374
|
+
* A fully qualified URL pointing to a page representing the User's online profile
|
|
375
|
+
*/
|
|
376
|
+
profileUrl?: string;
|
|
377
|
+
/**
|
|
378
|
+
* The user's title, such as "Vice President"
|
|
379
|
+
*/
|
|
380
|
+
title?: string;
|
|
381
|
+
/**
|
|
382
|
+
* Used to identify the relationship between the organization and the user
|
|
383
|
+
*/
|
|
384
|
+
userType?: string;
|
|
385
|
+
/**
|
|
386
|
+
* Indicates the User's preferred written or spoken language
|
|
387
|
+
*/
|
|
388
|
+
preferredLanguage?: string;
|
|
389
|
+
/**
|
|
390
|
+
* Used to indicate the User's default location for purposes of localizing items such as currency
|
|
391
|
+
*/
|
|
392
|
+
locale?: string;
|
|
393
|
+
/**
|
|
394
|
+
* The User's time zone in the "Olson" time zone database format
|
|
395
|
+
*/
|
|
396
|
+
timezone?: string;
|
|
397
|
+
/**
|
|
398
|
+
* A Boolean value indicating the User's administrative status
|
|
399
|
+
*/
|
|
400
|
+
active?: boolean;
|
|
401
|
+
/**
|
|
402
|
+
* The User's cleartext password
|
|
403
|
+
*/
|
|
404
|
+
password?: string;
|
|
405
|
+
/**
|
|
406
|
+
* Email addresses for the user
|
|
407
|
+
*/
|
|
408
|
+
emails?: Email[];
|
|
409
|
+
/**
|
|
410
|
+
* Phone numbers for the User
|
|
411
|
+
*/
|
|
412
|
+
phoneNumbers?: PhoneNumber[];
|
|
413
|
+
/**
|
|
414
|
+
* Instant messaging addresses for the User
|
|
415
|
+
*/
|
|
416
|
+
ims?: Array<{
|
|
417
|
+
value: string;
|
|
418
|
+
display?: string;
|
|
419
|
+
type?: string;
|
|
420
|
+
primary?: boolean;
|
|
421
|
+
}>;
|
|
422
|
+
/**
|
|
423
|
+
* URLs of photos of the User
|
|
424
|
+
*/
|
|
425
|
+
photos?: Array<{
|
|
426
|
+
value: string;
|
|
427
|
+
display?: string;
|
|
428
|
+
type?: string;
|
|
429
|
+
primary?: boolean;
|
|
430
|
+
}>;
|
|
431
|
+
/**
|
|
432
|
+
* Physical mailing addresses for this User
|
|
433
|
+
*/
|
|
434
|
+
addresses?: Address[];
|
|
435
|
+
/**
|
|
436
|
+
* A list of groups to which the user belongs
|
|
437
|
+
*/
|
|
438
|
+
groups?: Group[];
|
|
439
|
+
/**
|
|
440
|
+
* A list of entitlements for the User
|
|
441
|
+
*/
|
|
442
|
+
entitlements?: Array<{
|
|
443
|
+
value: string;
|
|
444
|
+
display?: string;
|
|
445
|
+
type?: string;
|
|
446
|
+
primary?: boolean;
|
|
447
|
+
}>;
|
|
448
|
+
/**
|
|
449
|
+
* A list of roles for the User
|
|
450
|
+
*/
|
|
451
|
+
roles?: Role[];
|
|
452
|
+
/**
|
|
453
|
+
* A list of certificates issued to the User
|
|
454
|
+
*/
|
|
455
|
+
x509Certificates?: X509Certificate[];
|
|
456
|
+
/**
|
|
457
|
+
* Enterprise User Extension
|
|
458
|
+
*/
|
|
459
|
+
'urn:ietf:params:scim:schemas:extension:enterprise:2.0:User'?: EnterpriseExtension;
|
|
460
|
+
/**
|
|
461
|
+
* REQUIRED. The schemas attribute is an array of Strings which allows introspection of the supported schema version
|
|
462
|
+
*/
|
|
463
|
+
schemas?: string[];
|
|
464
|
+
}
|
|
465
|
+
/**
|
|
466
|
+
* Creates a StandardSchemaV1 for validating SCIM User resources.
|
|
467
|
+
* @param vendor - The name of the vendor creating this schema
|
|
468
|
+
* @returns A StandardSchemaV1 instance for SCIM User resources
|
|
469
|
+
*/
|
|
470
|
+
declare function userSchema(vendor: string): StandardSchemaV1<Record<string, unknown>, User$1>;
|
|
471
|
+
/**
|
|
472
|
+
* Creates a StandardSchemaV1 for validating SCIM Group resources.
|
|
473
|
+
* @param vendor - The name of the vendor creating this schema
|
|
474
|
+
* @returns A StandardSchemaV1 instance for SCIM Group resources
|
|
475
|
+
*/
|
|
476
|
+
declare function groupResourceSchema(vendor: string): StandardSchemaV1<Record<string, unknown>, GroupResource>;
|
|
477
|
+
|
|
478
|
+
/**
|
|
479
|
+
* Group storage for persisting group data.
|
|
480
|
+
*
|
|
481
|
+
* Group stores are an optional extension for the IAM Groups functionality.
|
|
482
|
+
* They enable:
|
|
483
|
+
* - Caching group data locally for fast lookups
|
|
484
|
+
* - Receiving group provisioning from external IAM providers (SCIM server)
|
|
485
|
+
* - Storing groups close to your application (in-memory, Redis, database)
|
|
486
|
+
*
|
|
487
|
+
* ## Example Usage
|
|
488
|
+
*
|
|
489
|
+
* ```typescript
|
|
490
|
+
* import { InMemoryGroupStore } from '@enterprisestandard/react';
|
|
491
|
+
*
|
|
492
|
+
* const groupStore = new InMemoryGroupStore();
|
|
493
|
+
*
|
|
494
|
+
* // Store a group
|
|
495
|
+
* await groupStore.upsert({
|
|
496
|
+
* id: 'group-123',
|
|
497
|
+
* displayName: 'Administrators',
|
|
498
|
+
* createdAt: new Date(),
|
|
499
|
+
* updatedAt: new Date(),
|
|
500
|
+
* });
|
|
501
|
+
*
|
|
502
|
+
* // Look up groups
|
|
503
|
+
* const group = await groupStore.get('group-123');
|
|
504
|
+
* const allGroups = await groupStore.list();
|
|
505
|
+
* ```
|
|
506
|
+
*/
|
|
507
|
+
|
|
508
|
+
/**
|
|
509
|
+
* Stored group data with required id and tracking metadata.
|
|
510
|
+
*
|
|
511
|
+
* @template TExtended - Type-safe custom data that consumers can add to groups
|
|
512
|
+
*/
|
|
513
|
+
type StoredGroup<TExtended = {}> = {
|
|
514
|
+
/**
|
|
515
|
+
* Required unique identifier for the group.
|
|
516
|
+
* This is the primary key for group storage.
|
|
517
|
+
*/
|
|
518
|
+
id: string;
|
|
519
|
+
/**
|
|
520
|
+
* Required human-readable name for the group.
|
|
521
|
+
*/
|
|
522
|
+
displayName: string;
|
|
523
|
+
/**
|
|
524
|
+
* Optional external identifier from provisioning client.
|
|
525
|
+
*/
|
|
526
|
+
externalId?: string;
|
|
527
|
+
/**
|
|
528
|
+
* List of members in the group.
|
|
529
|
+
*/
|
|
530
|
+
members?: GroupMember[];
|
|
531
|
+
/**
|
|
532
|
+
* Timestamp when the group was first stored.
|
|
533
|
+
*/
|
|
534
|
+
createdAt: Date;
|
|
535
|
+
/**
|
|
536
|
+
* Timestamp when the group was last updated.
|
|
537
|
+
*/
|
|
538
|
+
updatedAt: Date;
|
|
539
|
+
} & TExtended;
|
|
540
|
+
/**
|
|
541
|
+
* Abstract interface for group storage backends.
|
|
542
|
+
*
|
|
543
|
+
* Consumers can implement this interface to use different storage backends:
|
|
544
|
+
* - In-memory (for development/testing)
|
|
545
|
+
* - Redis (for production with fast lookups)
|
|
546
|
+
* - Database (PostgreSQL, MySQL, etc.)
|
|
547
|
+
*
|
|
548
|
+
* @template TExtended - Type-safe custom data that consumers can add to groups
|
|
549
|
+
*/
|
|
550
|
+
interface GroupStore<TExtended = {}> {
|
|
551
|
+
/**
|
|
552
|
+
* Retrieve a group by its unique identifier.
|
|
553
|
+
*
|
|
554
|
+
* @param id - The group's unique identifier
|
|
555
|
+
* @returns The group if found, null otherwise
|
|
556
|
+
*/
|
|
557
|
+
get(id: string): Promise<StoredGroup<TExtended> | null>;
|
|
558
|
+
/**
|
|
559
|
+
* Retrieve a group by its external identifier.
|
|
560
|
+
*
|
|
561
|
+
* @param externalId - The external identifier from the provisioning client
|
|
562
|
+
* @returns The group if found, null otherwise
|
|
563
|
+
*/
|
|
564
|
+
getByExternalId(externalId: string): Promise<StoredGroup<TExtended> | null>;
|
|
565
|
+
/**
|
|
566
|
+
* Retrieve a group by its display name.
|
|
567
|
+
*
|
|
568
|
+
* @param displayName - The group's display name
|
|
569
|
+
* @returns The group if found, null otherwise
|
|
570
|
+
*/
|
|
571
|
+
getByDisplayName(displayName: string): Promise<StoredGroup<TExtended> | null>;
|
|
572
|
+
/**
|
|
573
|
+
* List all groups in the store.
|
|
574
|
+
*
|
|
575
|
+
* @returns Array of all stored groups
|
|
576
|
+
*/
|
|
577
|
+
list(): Promise<StoredGroup<TExtended>[]>;
|
|
578
|
+
/**
|
|
579
|
+
* Create or update a group in the store.
|
|
580
|
+
*
|
|
581
|
+
* If a group with the same `id` exists, it will be updated.
|
|
582
|
+
* Otherwise, a new group will be created.
|
|
583
|
+
*
|
|
584
|
+
* @param group - The group data to store
|
|
585
|
+
*/
|
|
586
|
+
upsert(group: StoredGroup<TExtended>): Promise<void>;
|
|
587
|
+
/**
|
|
588
|
+
* Delete a group by its unique identifier.
|
|
589
|
+
*
|
|
590
|
+
* @param id - The group's unique identifier to delete
|
|
591
|
+
*/
|
|
592
|
+
delete(id: string): Promise<void>;
|
|
593
|
+
/**
|
|
594
|
+
* Add a member to a group.
|
|
595
|
+
*
|
|
596
|
+
* @param groupId - The group's unique identifier
|
|
597
|
+
* @param member - The member to add
|
|
598
|
+
*/
|
|
599
|
+
addMember(groupId: string, member: GroupMember): Promise<void>;
|
|
600
|
+
/**
|
|
601
|
+
* Remove a member from a group.
|
|
602
|
+
*
|
|
603
|
+
* @param groupId - The group's unique identifier
|
|
604
|
+
* @param memberId - The member's value/id to remove
|
|
605
|
+
*/
|
|
606
|
+
removeMember(groupId: string, memberId: string): Promise<void>;
|
|
607
|
+
}
|
|
608
|
+
/**
|
|
609
|
+
* In-memory group store implementation using Maps.
|
|
610
|
+
*
|
|
611
|
+
* Suitable for:
|
|
612
|
+
* - Development and testing
|
|
613
|
+
* - Single-server deployments
|
|
614
|
+
* - Applications without high availability requirements
|
|
615
|
+
*
|
|
616
|
+
* NOT suitable for:
|
|
617
|
+
* - Multi-server deployments (groups not shared)
|
|
618
|
+
* - High availability scenarios (groups lost on restart)
|
|
619
|
+
* - Production applications with distributed architecture
|
|
620
|
+
*
|
|
621
|
+
* For production, implement GroupStore with Redis or a database.
|
|
622
|
+
*
|
|
623
|
+
* @template TExtended - Type-safe custom data that consumers can add to groups
|
|
624
|
+
*/
|
|
625
|
+
declare class InMemoryGroupStore<TExtended = {}> implements GroupStore<TExtended> {
|
|
626
|
+
/** Primary storage: id -> group */
|
|
627
|
+
private groups;
|
|
628
|
+
/** Secondary index: externalId -> id */
|
|
629
|
+
private externalIdIndex;
|
|
630
|
+
/** Secondary index: displayName (lowercase) -> id */
|
|
631
|
+
private displayNameIndex;
|
|
632
|
+
get(id: string): Promise<StoredGroup<TExtended> | null>;
|
|
633
|
+
getByExternalId(externalId: string): Promise<StoredGroup<TExtended> | null>;
|
|
634
|
+
getByDisplayName(displayName: string): Promise<StoredGroup<TExtended> | null>;
|
|
635
|
+
list(): Promise<StoredGroup<TExtended>[]>;
|
|
636
|
+
upsert(group: StoredGroup<TExtended>): Promise<void>;
|
|
637
|
+
delete(id: string): Promise<void>;
|
|
638
|
+
addMember(groupId: string, member: GroupMember): Promise<void>;
|
|
639
|
+
removeMember(groupId: string, memberId: string): Promise<void>;
|
|
640
|
+
}
|
|
641
|
+
|
|
642
|
+
/**
|
|
643
|
+
* Base user with simple, developer-friendly attributes.
|
|
644
|
+
* Extended by User (SSO) and EnterpriseUser (SCIM).
|
|
645
|
+
*/
|
|
646
|
+
interface BaseUser {
|
|
647
|
+
/**
|
|
648
|
+
* Unique identifier for the user
|
|
649
|
+
*/
|
|
650
|
+
id?: string;
|
|
651
|
+
/**
|
|
652
|
+
* REQUIRED. Unique identifier for login
|
|
653
|
+
*/
|
|
654
|
+
userName: string;
|
|
655
|
+
/**
|
|
656
|
+
* REQUIRED. Simple display name
|
|
657
|
+
*/
|
|
658
|
+
name: string;
|
|
659
|
+
/**
|
|
660
|
+
* REQUIRED. Primary email address
|
|
661
|
+
*/
|
|
662
|
+
email: string;
|
|
663
|
+
/**
|
|
664
|
+
* URL to user's avatar/profile picture
|
|
665
|
+
*/
|
|
666
|
+
avatarUrl?: string;
|
|
667
|
+
}
|
|
668
|
+
|
|
669
|
+
/**
|
|
670
|
+
* OIDC Code Flow Callback URL Parameters
|
|
671
|
+
* @see https://openid.net/specs/openid-connect-core-1_0.html#CodeFlowAuth
|
|
672
|
+
*/
|
|
673
|
+
interface OidcCallbackParams {
|
|
674
|
+
/**
|
|
675
|
+
* REQUIRED. The authorization code returned from the authorization server.
|
|
676
|
+
*/
|
|
677
|
+
code: string;
|
|
678
|
+
/**
|
|
679
|
+
* REQUIRED if the "state" parameter was present in the client authorization request.
|
|
680
|
+
* The exact value received from the client.
|
|
681
|
+
*/
|
|
682
|
+
state?: string;
|
|
683
|
+
/**
|
|
684
|
+
* RECOMMENDED. The session state value. Clients should use this to verify the session state.
|
|
685
|
+
*/
|
|
686
|
+
session_state?: string;
|
|
687
|
+
/**
|
|
688
|
+
* OAuth 2.0 error code if the authorization request failed.
|
|
689
|
+
*/
|
|
690
|
+
error?: string;
|
|
691
|
+
/**
|
|
692
|
+
* Human-readable ASCII text providing additional information for the error.
|
|
693
|
+
*/
|
|
694
|
+
error_description?: string;
|
|
695
|
+
/**
|
|
696
|
+
* A URI identifying a human-readable web page with information about the error.
|
|
697
|
+
*/
|
|
698
|
+
error_uri?: string;
|
|
699
|
+
/**
|
|
700
|
+
* The "iss" (issuer) parameter identifies the principal that issued the response.
|
|
701
|
+
* This is typically used in the implicit flow.
|
|
702
|
+
*/
|
|
703
|
+
iss?: string;
|
|
704
|
+
}
|
|
705
|
+
/**
|
|
706
|
+
* Creates a StandardSchemaV1 for validating OIDC callback URL parameters.
|
|
707
|
+
* @param vendor - The name of the vendor creating this schema
|
|
708
|
+
* @returns A StandardSchemaV1 instance for OIDC callback parameters
|
|
709
|
+
*/
|
|
710
|
+
declare function oidcCallbackSchema(vendor: string): StandardSchemaV1<Record<string, unknown>, OidcCallbackParams>;
|
|
711
|
+
/**
|
|
712
|
+
* Token Response from IdP
|
|
713
|
+
*/
|
|
714
|
+
interface TokenResponse {
|
|
715
|
+
access_token: string;
|
|
716
|
+
id_token: string;
|
|
717
|
+
refresh_token?: string;
|
|
718
|
+
token_type: string;
|
|
719
|
+
expires_in?: number;
|
|
720
|
+
scope?: string;
|
|
721
|
+
refresh_expires_in?: number;
|
|
722
|
+
session_state?: string;
|
|
723
|
+
expires?: string;
|
|
724
|
+
}
|
|
725
|
+
/**
|
|
726
|
+
* Creates a StandardSchemaV1 for validating OIDC Token Responses.
|
|
727
|
+
* @param vendor - The name of the vendor creating this schema
|
|
728
|
+
* @returns A StandardSchemaV1 instance for Token Response validation
|
|
729
|
+
*/
|
|
730
|
+
declare function tokenResponseSchema(vendor: string): StandardSchemaV1<Record<string, unknown>, TokenResponse>;
|
|
731
|
+
/**
|
|
732
|
+
* ID Token Claims
|
|
733
|
+
*/
|
|
734
|
+
interface IdTokenClaims {
|
|
735
|
+
iss?: string;
|
|
736
|
+
aud?: string;
|
|
737
|
+
exp?: number;
|
|
738
|
+
iat?: number;
|
|
739
|
+
sub?: string;
|
|
740
|
+
sid?: string;
|
|
741
|
+
name?: string;
|
|
742
|
+
email?: string;
|
|
743
|
+
preferred_username?: string;
|
|
744
|
+
picture?: string;
|
|
745
|
+
[key: string]: unknown;
|
|
746
|
+
}
|
|
747
|
+
/**
|
|
748
|
+
* Creates a StandardSchemaV1 for validating ID Token Claims.
|
|
749
|
+
* @param vendor - The name of the vendor creating this schema
|
|
750
|
+
* @returns A StandardSchemaV1 instance for ID Token Claims validation
|
|
751
|
+
*/
|
|
752
|
+
declare function idTokenClaimsSchema(vendor: string): StandardSchemaV1<Record<string, unknown>, IdTokenClaims>;
|
|
753
|
+
|
|
754
|
+
/**
|
|
755
|
+
* Primary user type for SSO/OIDC applications.
|
|
756
|
+
* Extends BaseUser with SSO-specific data.
|
|
757
|
+
*/
|
|
758
|
+
interface User extends BaseUser {
|
|
759
|
+
/**
|
|
760
|
+
* SSO/OIDC authentication data
|
|
761
|
+
*/
|
|
762
|
+
sso: {
|
|
763
|
+
/**
|
|
764
|
+
* ID Token claims from the identity provider
|
|
765
|
+
*/
|
|
766
|
+
profile: IdTokenClaims;
|
|
767
|
+
/**
|
|
768
|
+
* Tenant/organization information
|
|
769
|
+
*/
|
|
770
|
+
tenant: {
|
|
771
|
+
id: string;
|
|
772
|
+
name: string;
|
|
773
|
+
};
|
|
774
|
+
/**
|
|
775
|
+
* OAuth scopes granted
|
|
776
|
+
*/
|
|
777
|
+
scope?: string;
|
|
778
|
+
/**
|
|
779
|
+
* Token type (typically "Bearer")
|
|
780
|
+
*/
|
|
781
|
+
tokenType: string;
|
|
782
|
+
/**
|
|
783
|
+
* Session state from the identity provider
|
|
784
|
+
*/
|
|
785
|
+
sessionState?: string;
|
|
786
|
+
/**
|
|
787
|
+
* Token expiration time
|
|
788
|
+
*/
|
|
789
|
+
expires: Date;
|
|
790
|
+
};
|
|
791
|
+
}
|
|
792
|
+
|
|
793
|
+
/**
|
|
794
|
+
* User storage for persisting user profiles from SSO authentication.
|
|
795
|
+
*
|
|
796
|
+
* User stores are optional - the package works with JWT cookies alone.
|
|
797
|
+
* User stores are useful when you want to:
|
|
798
|
+
* - Cache user profiles for fast lookup
|
|
799
|
+
* - Store users close to your application (in-memory, Redis, etc.)
|
|
800
|
+
* - Avoid custom IAM/SCIM integration for simple use cases
|
|
801
|
+
*
|
|
802
|
+
* ## When to Use UserStore vs IAM
|
|
803
|
+
*
|
|
804
|
+
* **Use UserStore when:**
|
|
805
|
+
* - You just need fast user lookups without external systems
|
|
806
|
+
* - Users are managed by an external IdP and you just cache them locally
|
|
807
|
+
* - You want simple in-memory or Redis storage
|
|
808
|
+
*
|
|
809
|
+
* **Use IAM (SCIM) when:**
|
|
810
|
+
* - You need to provision users to an external identity provider
|
|
811
|
+
* - You need custom user attributes beyond what SSO provides
|
|
812
|
+
* - You need to sync users with enterprise directories
|
|
813
|
+
*
|
|
814
|
+
* ## Example Usage
|
|
815
|
+
*
|
|
816
|
+
* ```typescript
|
|
817
|
+
* import { sso, InMemoryUserStore } from '@enterprisestandard/react/server';
|
|
818
|
+
*
|
|
819
|
+
* const userStore = new InMemoryUserStore();
|
|
820
|
+
*
|
|
821
|
+
* const auth = sso({
|
|
822
|
+
* // ... other config
|
|
823
|
+
* user_store: userStore,
|
|
824
|
+
* });
|
|
825
|
+
*
|
|
826
|
+
* // Later, look up users
|
|
827
|
+
* const user = await userStore.get('user-sub-id');
|
|
828
|
+
* const userByEmail = await userStore.getByEmail('user@example.com');
|
|
829
|
+
* ```
|
|
830
|
+
*/
|
|
831
|
+
|
|
832
|
+
/**
|
|
833
|
+
* Stored user data with required id and tracking metadata.
|
|
834
|
+
*
|
|
835
|
+
* Extends the SSO User type with:
|
|
836
|
+
* - Required `id` (the `sub` claim from the IdP)
|
|
837
|
+
* - Timestamps for tracking when users were first seen and last updated
|
|
838
|
+
* - Optional custom extended data
|
|
839
|
+
*
|
|
840
|
+
* @template TExtended - Type-safe custom data that consumers can add to users
|
|
841
|
+
*/
|
|
842
|
+
type StoredUser<TExtended = {}> = User & {
|
|
843
|
+
/**
|
|
844
|
+
* Required unique identifier (the `sub` claim from the IdP).
|
|
845
|
+
* This is the primary key for user storage.
|
|
846
|
+
*/
|
|
847
|
+
id: string;
|
|
848
|
+
/**
|
|
849
|
+
* Timestamp when the user was first stored.
|
|
850
|
+
*/
|
|
851
|
+
createdAt: Date;
|
|
852
|
+
/**
|
|
853
|
+
* Timestamp when the user was last updated (e.g., on re-login).
|
|
854
|
+
*/
|
|
855
|
+
updatedAt: Date;
|
|
856
|
+
} & TExtended;
|
|
857
|
+
/**
|
|
858
|
+
* Abstract interface for user storage backends.
|
|
859
|
+
*
|
|
860
|
+
* Consumers can implement this interface to use different storage backends:
|
|
861
|
+
* - In-memory (for development/testing)
|
|
862
|
+
* - Redis (for production with fast lookups)
|
|
863
|
+
* - Database (PostgreSQL, MySQL, etc.)
|
|
864
|
+
*
|
|
865
|
+
* @template TExtended - Type-safe custom data that consumers can add to users
|
|
866
|
+
*
|
|
867
|
+
* @example
|
|
868
|
+
* ```typescript
|
|
869
|
+
* // Custom user data
|
|
870
|
+
* type MyUserData = {
|
|
871
|
+
* department: string;
|
|
872
|
+
* roles: string[];
|
|
873
|
+
* };
|
|
874
|
+
*
|
|
875
|
+
* // Implement custom store
|
|
876
|
+
* class RedisUserStore implements UserStore<MyUserData> {
|
|
877
|
+
* async get(sub: string): Promise<StoredUser<MyUserData> | null> {
|
|
878
|
+
* const data = await redis.get(`user:${sub}`);
|
|
879
|
+
* return data ? JSON.parse(data) : null;
|
|
880
|
+
* }
|
|
881
|
+
* // ... other methods
|
|
882
|
+
* }
|
|
883
|
+
* ```
|
|
884
|
+
*/
|
|
885
|
+
interface UserStore<TExtended = {}> {
|
|
886
|
+
/**
|
|
887
|
+
* Retrieve a user by their subject identifier (sub).
|
|
888
|
+
*
|
|
889
|
+
* @param sub - The user's unique identifier from the IdP
|
|
890
|
+
* @returns The user if found, null otherwise
|
|
891
|
+
*/
|
|
892
|
+
get(sub: string): Promise<StoredUser<TExtended> | null>;
|
|
893
|
+
/**
|
|
894
|
+
* Retrieve a user by their email address.
|
|
895
|
+
*
|
|
896
|
+
* @param email - The user's email address
|
|
897
|
+
* @returns The user if found, null otherwise
|
|
898
|
+
*/
|
|
899
|
+
getByEmail(email: string): Promise<StoredUser<TExtended> | null>;
|
|
900
|
+
/**
|
|
901
|
+
* Retrieve a user by their username.
|
|
902
|
+
*
|
|
903
|
+
* @param userName - The user's username
|
|
904
|
+
* @returns The user if found, null otherwise
|
|
905
|
+
*/
|
|
906
|
+
getByUserName(userName: string): Promise<StoredUser<TExtended> | null>;
|
|
907
|
+
/**
|
|
908
|
+
* Create or update a user in the store.
|
|
909
|
+
*
|
|
910
|
+
* If a user with the same `id` (sub) exists, it will be updated.
|
|
911
|
+
* Otherwise, a new user will be created.
|
|
912
|
+
*
|
|
913
|
+
* @param user - The user data to store
|
|
914
|
+
*/
|
|
915
|
+
upsert(user: StoredUser<TExtended>): Promise<void>;
|
|
916
|
+
/**
|
|
917
|
+
* Delete a user by their subject identifier (sub).
|
|
918
|
+
*
|
|
919
|
+
* @param sub - The user's unique identifier to delete
|
|
920
|
+
*/
|
|
921
|
+
delete(sub: string): Promise<void>;
|
|
922
|
+
}
|
|
923
|
+
/**
|
|
924
|
+
* In-memory user store implementation using Maps.
|
|
925
|
+
*
|
|
926
|
+
* Suitable for:
|
|
927
|
+
* - Development and testing
|
|
928
|
+
* - Single-server deployments
|
|
929
|
+
* - Applications without high availability requirements
|
|
930
|
+
*
|
|
931
|
+
* NOT suitable for:
|
|
932
|
+
* - Multi-server deployments (users not shared)
|
|
933
|
+
* - High availability scenarios (users lost on restart)
|
|
934
|
+
* - Production applications with distributed architecture
|
|
935
|
+
*
|
|
936
|
+
* For production, implement UserStore with Redis or a database.
|
|
937
|
+
*
|
|
938
|
+
* @template TExtended - Type-safe custom data that consumers can add to users
|
|
939
|
+
*/
|
|
940
|
+
declare class InMemoryUserStore<TExtended = {}> implements UserStore<TExtended> {
|
|
941
|
+
/** Primary storage: sub -> user */
|
|
942
|
+
private users;
|
|
943
|
+
/** Secondary index: email -> sub */
|
|
944
|
+
private emailIndex;
|
|
945
|
+
/** Secondary index: userName -> sub */
|
|
946
|
+
private userNameIndex;
|
|
947
|
+
get(sub: string): Promise<StoredUser<TExtended> | null>;
|
|
948
|
+
getByEmail(email: string): Promise<StoredUser<TExtended> | null>;
|
|
949
|
+
getByUserName(userName: string): Promise<StoredUser<TExtended> | null>;
|
|
950
|
+
upsert(user: StoredUser<TExtended>): Promise<void>;
|
|
951
|
+
delete(sub: string): Promise<void>;
|
|
952
|
+
}
|
|
953
|
+
|
|
954
|
+
/**
|
|
955
|
+
* JWT Assertion Claims for OAuth2 JWT Bearer Grant (RFC 7523) and OAuth2 Access Tokens
|
|
956
|
+
* @see https://datatracker.ietf.org/doc/html/rfc7523
|
|
957
|
+
* @see https://datatracker.ietf.org/doc/html/rfc9068
|
|
958
|
+
*/
|
|
959
|
+
interface JWTAssertionClaims {
|
|
960
|
+
/**
|
|
961
|
+
* REQUIRED. Issuer - the workload identity (e.g., SPIFFE ID) or authorization server
|
|
962
|
+
*/
|
|
963
|
+
iss: string;
|
|
964
|
+
/**
|
|
965
|
+
* REQUIRED. Subject - the workload identity or service account
|
|
966
|
+
*/
|
|
967
|
+
sub: string;
|
|
968
|
+
/**
|
|
969
|
+
* OPTIONAL. Audience - may be a string or array of strings
|
|
970
|
+
* Note: Required for JWT assertions, but may be absent in OAuth2 access tokens
|
|
971
|
+
*/
|
|
972
|
+
aud?: string | string[];
|
|
973
|
+
/**
|
|
974
|
+
* REQUIRED. Expiration time (Unix timestamp)
|
|
975
|
+
*/
|
|
976
|
+
exp: number;
|
|
977
|
+
/**
|
|
978
|
+
* REQUIRED. Issued at time (Unix timestamp)
|
|
979
|
+
*/
|
|
980
|
+
iat: number;
|
|
981
|
+
/**
|
|
982
|
+
* OPTIONAL. JWT ID - unique identifier for this token
|
|
983
|
+
* Note: Required for JWT assertions, optional for access tokens
|
|
984
|
+
*/
|
|
985
|
+
jti?: string;
|
|
986
|
+
/**
|
|
987
|
+
* OPTIONAL. Requested OAuth scopes (space-delimited)
|
|
988
|
+
*/
|
|
989
|
+
scope?: string;
|
|
990
|
+
/**
|
|
991
|
+
* Allow additional claims for extensibility
|
|
992
|
+
*/
|
|
993
|
+
[key: string]: unknown;
|
|
994
|
+
}
|
|
995
|
+
/**
|
|
996
|
+
* Creates a StandardSchemaV1 for validating JWT Assertion Claims.
|
|
997
|
+
* @param vendor - The name of the vendor creating this schema
|
|
998
|
+
* @returns A StandardSchemaV1 instance for JWT Assertion Claims validation
|
|
999
|
+
*/
|
|
1000
|
+
declare function jwtAssertionClaimsSchema(vendor: string): StandardSchemaV1<Record<string, unknown>, JWTAssertionClaims>;
|
|
1001
|
+
/**
|
|
1002
|
+
* Workload Token Response from OAuth2 token endpoint
|
|
1003
|
+
* @see https://datatracker.ietf.org/doc/html/rfc6749#section-5.1
|
|
1004
|
+
*/
|
|
1005
|
+
interface WorkloadTokenResponse {
|
|
1006
|
+
/**
|
|
1007
|
+
* REQUIRED. The access token issued by the authorization server.
|
|
1008
|
+
*/
|
|
1009
|
+
access_token: string;
|
|
1010
|
+
/**
|
|
1011
|
+
* REQUIRED. The type of the token (typically "Bearer").
|
|
1012
|
+
*/
|
|
1013
|
+
token_type: string;
|
|
1014
|
+
/**
|
|
1015
|
+
* RECOMMENDED. The lifetime in seconds of the access token.
|
|
1016
|
+
*/
|
|
1017
|
+
expires_in?: number;
|
|
1018
|
+
/**
|
|
1019
|
+
* OPTIONAL. The scope of the access token.
|
|
1020
|
+
*/
|
|
1021
|
+
scope?: string;
|
|
1022
|
+
/**
|
|
1023
|
+
* OPTIONAL. The refresh token (rarely used for workload identities).
|
|
1024
|
+
*/
|
|
1025
|
+
refresh_token?: string;
|
|
1026
|
+
/**
|
|
1027
|
+
* OPTIONAL. The expiration time as an ISO 8601 string.
|
|
1028
|
+
*/
|
|
1029
|
+
expires?: string;
|
|
1030
|
+
}
|
|
1031
|
+
/**
|
|
1032
|
+
* Creates a StandardSchemaV1 for validating Workload Token Responses.
|
|
1033
|
+
* @param vendor - The name of the vendor creating this schema
|
|
1034
|
+
* @returns A StandardSchemaV1 instance for Workload Token Response validation
|
|
1035
|
+
*/
|
|
1036
|
+
declare function workloadTokenResponseSchema(vendor: string): StandardSchemaV1<Record<string, unknown>, WorkloadTokenResponse>;
|
|
1037
|
+
/**
|
|
1038
|
+
* Token Validation Result
|
|
1039
|
+
*/
|
|
1040
|
+
interface TokenValidationResult {
|
|
1041
|
+
/**
|
|
1042
|
+
* Whether the token is valid
|
|
1043
|
+
*/
|
|
1044
|
+
valid: boolean;
|
|
1045
|
+
/**
|
|
1046
|
+
* The decoded and validated claims (if valid)
|
|
1047
|
+
*/
|
|
1048
|
+
claims?: JWTAssertionClaims;
|
|
1049
|
+
/**
|
|
1050
|
+
* Error message (if invalid)
|
|
1051
|
+
*/
|
|
1052
|
+
error?: string;
|
|
1053
|
+
/**
|
|
1054
|
+
* Token expiration time (if valid)
|
|
1055
|
+
*/
|
|
1056
|
+
expiresAt?: Date;
|
|
1057
|
+
}
|
|
1058
|
+
|
|
1059
|
+
/**
|
|
1060
|
+
* Token caching for workload identity authentication.
|
|
1061
|
+
*
|
|
1062
|
+
* Token stores are optional but recommended for performance - they enable:
|
|
1063
|
+
* - Token caching to avoid repeated token acquisition
|
|
1064
|
+
* - Automatic token refresh before expiration
|
|
1065
|
+
* - Reduced load on authorization servers
|
|
1066
|
+
*
|
|
1067
|
+
* ## Token Caching Strategy
|
|
1068
|
+
*
|
|
1069
|
+
* Unlike session stores for user authentication, workload token stores cache
|
|
1070
|
+
* short-lived access tokens (typically 5 minutes) for service-to-service calls.
|
|
1071
|
+
*
|
|
1072
|
+
* **Default Behavior:**
|
|
1073
|
+
* - Tokens cached with 5-minute TTL
|
|
1074
|
+
* - Auto-refresh 60 seconds before expiration
|
|
1075
|
+
* - Expired tokens automatically removed
|
|
1076
|
+
*
|
|
1077
|
+
* ## Performance Characteristics
|
|
1078
|
+
*
|
|
1079
|
+
* | Backend | Lookup Time | Use Case |
|
|
1080
|
+
* |--------------|-------------|----------------------------|
|
|
1081
|
+
* | InMemory | <0.00005ms | Single-server deployments |
|
|
1082
|
+
* | Redis | 1-2ms | Multi-server deployments |
|
|
1083
|
+
* | Database | 5-20ms | Persistent token storage |
|
|
1084
|
+
*
|
|
1085
|
+
* ## Example Usage
|
|
1086
|
+
*
|
|
1087
|
+
* ```typescript
|
|
1088
|
+
* import { workload, InMemoryWorkloadTokenStore } from '@enterprisestandard/react/server';
|
|
1089
|
+
*
|
|
1090
|
+
* // With token caching
|
|
1091
|
+
* const workloadAuth = workload({
|
|
1092
|
+
* // ... other config
|
|
1093
|
+
* token_store: new InMemoryWorkloadTokenStore(),
|
|
1094
|
+
* auto_refresh: true, // Refresh before expiry
|
|
1095
|
+
* });
|
|
1096
|
+
*
|
|
1097
|
+
* // Without token caching (fetch new token each time)
|
|
1098
|
+
* const workloadAuth = workload({
|
|
1099
|
+
* // ... config without token_store
|
|
1100
|
+
* });
|
|
1101
|
+
* ```
|
|
1102
|
+
*/
|
|
1103
|
+
/**
|
|
1104
|
+
* Cached workload token data.
|
|
1105
|
+
*
|
|
1106
|
+
* @template TExtended - Type-safe custom data that consumers can add to cached tokens
|
|
1107
|
+
*/
|
|
1108
|
+
type CachedWorkloadToken<TExtended = object> = {
|
|
1109
|
+
/**
|
|
1110
|
+
* Workload identifier (typically SPIFFE ID).
|
|
1111
|
+
* Used as the primary key for token lookup.
|
|
1112
|
+
*/
|
|
1113
|
+
workload_id: string;
|
|
1114
|
+
/**
|
|
1115
|
+
* OAuth2 access token (Bearer token)
|
|
1116
|
+
*/
|
|
1117
|
+
access_token: string;
|
|
1118
|
+
/**
|
|
1119
|
+
* Token type (always "Bearer" for OAuth2)
|
|
1120
|
+
*/
|
|
1121
|
+
token_type: string;
|
|
1122
|
+
/**
|
|
1123
|
+
* OAuth2 scopes granted for this token
|
|
1124
|
+
*/
|
|
1125
|
+
scope?: string;
|
|
1126
|
+
/**
|
|
1127
|
+
* Timestamp when the token expires.
|
|
1128
|
+
* Used for automatic cleanup and refresh logic.
|
|
1129
|
+
*/
|
|
1130
|
+
expires_at: Date;
|
|
1131
|
+
/**
|
|
1132
|
+
* Timestamp when the token was created/cached.
|
|
1133
|
+
*/
|
|
1134
|
+
created_at: Date;
|
|
1135
|
+
/**
|
|
1136
|
+
* Optional refresh token (rarely used for workload identities)
|
|
1137
|
+
*/
|
|
1138
|
+
refresh_token?: string;
|
|
1139
|
+
} & TExtended;
|
|
1140
|
+
/**
|
|
1141
|
+
* Abstract interface for workload token storage backends.
|
|
1142
|
+
*
|
|
1143
|
+
* Consumers can implement this interface to use different storage backends:
|
|
1144
|
+
* - Redis (recommended for multi-server deployments)
|
|
1145
|
+
* - Database (PostgreSQL, MySQL, etc. for persistence)
|
|
1146
|
+
* - Distributed cache (Memcached, etc.)
|
|
1147
|
+
* - Custom solutions
|
|
1148
|
+
*
|
|
1149
|
+
* @template TExtended - Type-safe custom data that consumers can add to cached tokens
|
|
1150
|
+
*
|
|
1151
|
+
* @example
|
|
1152
|
+
* ```typescript
|
|
1153
|
+
* // Custom token cache data
|
|
1154
|
+
* type MyTokenData = {
|
|
1155
|
+
* environment: string;
|
|
1156
|
+
* region: string;
|
|
1157
|
+
* };
|
|
1158
|
+
*
|
|
1159
|
+
* // Implement custom store with Redis
|
|
1160
|
+
* class RedisWorkloadTokenStore implements WorkloadTokenStore<MyTokenData> {
|
|
1161
|
+
* async set(token: CachedWorkloadToken<MyTokenData>): Promise<void> {
|
|
1162
|
+
* const ttl = Math.floor((token.expires_at.getTime() - Date.now()) / 1000);
|
|
1163
|
+
* await redis.setex(
|
|
1164
|
+
* `workload:token:${token.workload_id}`,
|
|
1165
|
+
* ttl,
|
|
1166
|
+
* JSON.stringify(token)
|
|
1167
|
+
* );
|
|
1168
|
+
* }
|
|
1169
|
+
*
|
|
1170
|
+
* async get(workload_id: string): Promise<CachedWorkloadToken<MyTokenData> | null> {
|
|
1171
|
+
* const data = await redis.get(`workload:token:${workload_id}`);
|
|
1172
|
+
* if (!data) return null;
|
|
1173
|
+
* const token = JSON.parse(data);
|
|
1174
|
+
* // Convert date strings back to Date objects
|
|
1175
|
+
* token.expires_at = new Date(token.expires_at);
|
|
1176
|
+
* token.created_at = new Date(token.created_at);
|
|
1177
|
+
* return token;
|
|
1178
|
+
* }
|
|
1179
|
+
*
|
|
1180
|
+
* // ... other methods
|
|
1181
|
+
* }
|
|
1182
|
+
* ```
|
|
1183
|
+
*/
|
|
1184
|
+
interface WorkloadTokenStore<TExtended = object> {
|
|
1185
|
+
/**
|
|
1186
|
+
* Store or update a workload token in the cache.
|
|
1187
|
+
*
|
|
1188
|
+
* @param token - The token data to cache
|
|
1189
|
+
*/
|
|
1190
|
+
set(token: CachedWorkloadToken<TExtended>): Promise<void>;
|
|
1191
|
+
/**
|
|
1192
|
+
* Retrieve a cached token by workload ID.
|
|
1193
|
+
*
|
|
1194
|
+
* @param workload_id - The workload identifier (e.g., SPIFFE ID)
|
|
1195
|
+
* @returns The cached token if found and not expired, null otherwise
|
|
1196
|
+
*/
|
|
1197
|
+
get(workload_id: string): Promise<CachedWorkloadToken<TExtended> | null>;
|
|
1198
|
+
/**
|
|
1199
|
+
* Delete a cached token by workload ID.
|
|
1200
|
+
*
|
|
1201
|
+
* Used when explicitly revoking tokens or clearing cache.
|
|
1202
|
+
*
|
|
1203
|
+
* @param workload_id - The workload identifier to remove
|
|
1204
|
+
*/
|
|
1205
|
+
delete(workload_id: string): Promise<void>;
|
|
1206
|
+
/**
|
|
1207
|
+
* Check if a valid (non-expired) token exists for a workload.
|
|
1208
|
+
*
|
|
1209
|
+
* @param workload_id - The workload identifier to check
|
|
1210
|
+
* @returns true if a valid token exists, false otherwise
|
|
1211
|
+
*/
|
|
1212
|
+
isValid(workload_id: string): Promise<boolean>;
|
|
1213
|
+
/**
|
|
1214
|
+
* Remove all expired tokens from the cache.
|
|
1215
|
+
*
|
|
1216
|
+
* Should be called periodically to prevent memory leaks.
|
|
1217
|
+
*/
|
|
1218
|
+
cleanup(): Promise<void>;
|
|
1219
|
+
}
|
|
1220
|
+
/**
|
|
1221
|
+
* In-memory workload token store implementation using Maps.
|
|
1222
|
+
*
|
|
1223
|
+
* Suitable for:
|
|
1224
|
+
* - Development and testing
|
|
1225
|
+
* - Single-server deployments
|
|
1226
|
+
* - Applications without high availability requirements
|
|
1227
|
+
*
|
|
1228
|
+
* NOT suitable for:
|
|
1229
|
+
* - Multi-server deployments (tokens not shared across instances)
|
|
1230
|
+
* - High availability scenarios (tokens lost on restart)
|
|
1231
|
+
* - Production applications with distributed architecture
|
|
1232
|
+
*
|
|
1233
|
+
* For production multi-server deployments, implement WorkloadTokenStore with Redis.
|
|
1234
|
+
*
|
|
1235
|
+
* @template TExtended - Type-safe custom data that consumers can add to cached tokens
|
|
1236
|
+
*/
|
|
1237
|
+
declare class InMemoryWorkloadTokenStore<TExtended = object> implements WorkloadTokenStore<TExtended> {
|
|
1238
|
+
private tokens;
|
|
1239
|
+
set(token: CachedWorkloadToken<TExtended>): Promise<void>;
|
|
1240
|
+
get(workload_id: string): Promise<CachedWorkloadToken<TExtended> | null>;
|
|
1241
|
+
delete(workload_id: string): Promise<void>;
|
|
1242
|
+
isValid(workload_id: string): Promise<boolean>;
|
|
1243
|
+
cleanup(): Promise<void>;
|
|
1244
|
+
}
|
|
1245
|
+
|
|
1246
|
+
/**
|
|
1247
|
+
* Common fields shared across all workload authentication modes
|
|
1248
|
+
*/
|
|
1249
|
+
type WorkloadConfigBase = {
|
|
1250
|
+
/**
|
|
1251
|
+
* OAuth2 token endpoint URL
|
|
1252
|
+
* REQUIRED for client role (token acquisition)
|
|
1253
|
+
*/
|
|
1254
|
+
token_url?: string;
|
|
1255
|
+
/**
|
|
1256
|
+
* JWKS endpoint URL for public key retrieval
|
|
1257
|
+
* REQUIRED for server role (token validation)
|
|
1258
|
+
*/
|
|
1259
|
+
jwks_uri?: string;
|
|
1260
|
+
/**
|
|
1261
|
+
* Expected token issuer URL for validation
|
|
1262
|
+
* RECOMMENDED for server role (token validation)
|
|
1263
|
+
*/
|
|
1264
|
+
issuer?: string;
|
|
1265
|
+
/**
|
|
1266
|
+
* Target audience for tokens
|
|
1267
|
+
*/
|
|
1268
|
+
audience?: string;
|
|
1269
|
+
/**
|
|
1270
|
+
* Default OAuth2 scopes (space-delimited)
|
|
1271
|
+
*/
|
|
1272
|
+
scope?: string;
|
|
1273
|
+
/**
|
|
1274
|
+
* JWT assertion/token lifetime in seconds
|
|
1275
|
+
* @default 300 (5 minutes)
|
|
1276
|
+
*/
|
|
1277
|
+
token_lifetime?: number;
|
|
1278
|
+
/**
|
|
1279
|
+
* Refresh threshold in seconds (refresh token this many seconds before expiry)
|
|
1280
|
+
* @default 60
|
|
1281
|
+
*/
|
|
1282
|
+
refresh_threshold?: number;
|
|
1283
|
+
/**
|
|
1284
|
+
* Optional token store for caching access tokens
|
|
1285
|
+
*/
|
|
1286
|
+
token_store?: WorkloadTokenStore;
|
|
1287
|
+
/**
|
|
1288
|
+
* Automatically refresh tokens before expiration
|
|
1289
|
+
* @default true
|
|
1290
|
+
*/
|
|
1291
|
+
auto_refresh?: boolean;
|
|
1292
|
+
/**
|
|
1293
|
+
* Optional RFC 7009 token revocation endpoint
|
|
1294
|
+
*/
|
|
1295
|
+
revocation_endpoint?: string;
|
|
1296
|
+
/**
|
|
1297
|
+
* Optional handler defaults (merged with per-call overrides in `handler`)
|
|
1298
|
+
*/
|
|
1299
|
+
tokenUrl?: string;
|
|
1300
|
+
validateUrl?: string;
|
|
1301
|
+
jwksUrl?: string;
|
|
1302
|
+
refreshUrl?: string;
|
|
1303
|
+
validation?: {
|
|
1304
|
+
jwtAssertionClaims?: StandardSchemaV1<unknown, JWTAssertionClaims>;
|
|
1305
|
+
tokenResponse?: StandardSchemaV1<unknown, WorkloadTokenResponse>;
|
|
1306
|
+
};
|
|
1307
|
+
};
|
|
1308
|
+
/**
|
|
1309
|
+
* JWT Bearer Grant (RFC 7523) Configuration
|
|
1310
|
+
*
|
|
1311
|
+
* Used for SPIFFE-style workload identities where services have their own
|
|
1312
|
+
* cryptographic identity and sign their own JWT assertions.
|
|
1313
|
+
*
|
|
1314
|
+
* @example
|
|
1315
|
+
* ```json
|
|
1316
|
+
* {
|
|
1317
|
+
* "token_url": "https://auth.example.com/oauth/token",
|
|
1318
|
+
* "jwks_uri": "https://auth.example.com/.well-known/jwks.json",
|
|
1319
|
+
* "workload_id": "spiffe://trust-domain/ns/service",
|
|
1320
|
+
* "audience": "https://auth.example.com/oauth/token",
|
|
1321
|
+
* "private_key": "-----BEGIN PRIVATE KEY-----...",
|
|
1322
|
+
* "algorithm": "RS256"
|
|
1323
|
+
* }
|
|
1324
|
+
* ```
|
|
1325
|
+
*/
|
|
1326
|
+
type JwtBearerWorkloadConfig = WorkloadConfigBase & {
|
|
1327
|
+
/**
|
|
1328
|
+
* Workload identifier (e.g., SPIFFE ID: spiffe://trust-domain/namespace/service)
|
|
1329
|
+
* REQUIRED for JWT Bearer Grant mode
|
|
1330
|
+
*/
|
|
1331
|
+
workload_id?: string;
|
|
1332
|
+
/**
|
|
1333
|
+
* PEM-encoded private key for signing JWT assertions
|
|
1334
|
+
* REQUIRED for client role in JWT Bearer Grant mode
|
|
1335
|
+
*/
|
|
1336
|
+
private_key?: string;
|
|
1337
|
+
/**
|
|
1338
|
+
* Key ID (kid) to include in JWT header for key rotation support
|
|
1339
|
+
*/
|
|
1340
|
+
key_id?: string;
|
|
1341
|
+
/**
|
|
1342
|
+
* JWT signing algorithm
|
|
1343
|
+
* @default 'RS256'
|
|
1344
|
+
*/
|
|
1345
|
+
algorithm?: 'RS256' | 'RS384' | 'RS512' | 'ES256' | 'ES384' | 'ES512';
|
|
1346
|
+
};
|
|
1347
|
+
/**
|
|
1348
|
+
* OAuth2 Client Credentials Configuration
|
|
1349
|
+
*
|
|
1350
|
+
* Standard OAuth2 Client Credentials Grant (RFC 6749 Section 4.4).
|
|
1351
|
+
* Used with identity providers like Keycloak for service-to-service authentication.
|
|
1352
|
+
*
|
|
1353
|
+
* @example
|
|
1354
|
+
* ```json
|
|
1355
|
+
* {
|
|
1356
|
+
* "token_url": "https://sso.example.com/realms/myrealm/protocol/openid-connect/token",
|
|
1357
|
+
* "jwks_uri": "https://sso.example.com/realms/myrealm/protocol/openid-connect/certs",
|
|
1358
|
+
* "client_id": "my-service",
|
|
1359
|
+
* "client_secret": "secret-from-idp",
|
|
1360
|
+
* "issuer": "https://sso.example.com/realms/myrealm",
|
|
1361
|
+
* "scope": "api:read api:write"
|
|
1362
|
+
* }
|
|
1363
|
+
* ```
|
|
1364
|
+
*/
|
|
1365
|
+
type ClientCredentialsWorkloadConfig = WorkloadConfigBase & {
|
|
1366
|
+
/**
|
|
1367
|
+
* OAuth2 client identifier registered with the authorization server
|
|
1368
|
+
* REQUIRED for Client Credentials mode
|
|
1369
|
+
*/
|
|
1370
|
+
client_id?: string;
|
|
1371
|
+
/**
|
|
1372
|
+
* OAuth2 client secret
|
|
1373
|
+
* REQUIRED for Client Credentials mode
|
|
1374
|
+
*/
|
|
1375
|
+
client_secret?: string;
|
|
1376
|
+
};
|
|
1377
|
+
/**
|
|
1378
|
+
* Server-Only Workload Configuration
|
|
1379
|
+
*
|
|
1380
|
+
* Used when a service only needs to validate incoming workload tokens,
|
|
1381
|
+
* not acquire tokens for outbound calls. Requires only jwks_uri for
|
|
1382
|
+
* public key retrieval.
|
|
1383
|
+
*
|
|
1384
|
+
* @example
|
|
1385
|
+
* ```json
|
|
1386
|
+
* {
|
|
1387
|
+
* "jwks_uri": "https://sso.example.com/realms/myrealm/protocol/openid-connect/certs",
|
|
1388
|
+
* "issuer": "https://sso.example.com/realms/myrealm"
|
|
1389
|
+
* }
|
|
1390
|
+
* ```
|
|
1391
|
+
*/
|
|
1392
|
+
type ServerOnlyWorkloadConfig = WorkloadConfigBase;
|
|
1393
|
+
/**
|
|
1394
|
+
* Workload Identity Authentication Configuration
|
|
1395
|
+
*
|
|
1396
|
+
* Union type supporting multiple authentication modes. The mode is automatically
|
|
1397
|
+
* detected based on which fields are present:
|
|
1398
|
+
*
|
|
1399
|
+
* - **JWT Bearer Grant**: Requires `workload_id` + `private_key`
|
|
1400
|
+
* - **Client Credentials**: Requires `client_id` + `client_secret`
|
|
1401
|
+
* - **Server-Only**: Only `jwks_uri` (and optionally `issuer`) for token validation
|
|
1402
|
+
*
|
|
1403
|
+
* The developer uses the same API regardless of mode - the library handles the details.
|
|
1404
|
+
*/
|
|
1405
|
+
type WorkloadConfig = JwtBearerWorkloadConfig | ClientCredentialsWorkloadConfig | ServerOnlyWorkloadConfig;
|
|
1406
|
+
/**
|
|
1407
|
+
* Workload Identity extracted from validated tokens
|
|
1408
|
+
*/
|
|
1409
|
+
type WorkloadIdentity = {
|
|
1410
|
+
/**
|
|
1411
|
+
* Workload identifier (for JWT Bearer Grant tokens)
|
|
1412
|
+
*/
|
|
1413
|
+
workload_id?: string;
|
|
1414
|
+
/**
|
|
1415
|
+
* Client identifier (for OAuth2 Client Credentials tokens)
|
|
1416
|
+
*/
|
|
1417
|
+
client_id?: string;
|
|
1418
|
+
/**
|
|
1419
|
+
* Granted scopes
|
|
1420
|
+
*/
|
|
1421
|
+
scope?: string;
|
|
1422
|
+
/**
|
|
1423
|
+
* Full JWT claims from the token
|
|
1424
|
+
*/
|
|
1425
|
+
claims: JWTAssertionClaims;
|
|
1426
|
+
};
|
|
1427
|
+
/**
|
|
1428
|
+
* Workload Identity Authentication Interface
|
|
1429
|
+
*/
|
|
1430
|
+
type Workload = WorkloadConfig & {
|
|
1431
|
+
getToken: (scope?: string) => Promise<string>;
|
|
1432
|
+
refreshToken: () => Promise<WorkloadTokenResponse>;
|
|
1433
|
+
generateJWTAssertion: (scope?: string) => Promise<string>;
|
|
1434
|
+
revokeToken: (token: string) => Promise<void>;
|
|
1435
|
+
validateToken: (token: string, validation?: WorkloadConfig['validation']) => Promise<TokenValidationResult>;
|
|
1436
|
+
getWorkload: (request: Request) => Promise<WorkloadIdentity | undefined>;
|
|
1437
|
+
parseJWT: (token: string, validation?: WorkloadConfig['validation']) => Promise<JWTAssertionClaims>;
|
|
1438
|
+
handler: (request: Request) => Promise<Response>;
|
|
1439
|
+
};
|
|
1440
|
+
/**
|
|
1441
|
+
* Create a workload identity authentication instance
|
|
1442
|
+
*
|
|
1443
|
+
* @param config - Workload authentication configuration
|
|
1444
|
+
* @returns Workload authentication interface
|
|
1445
|
+
*
|
|
1446
|
+
* @example
|
|
1447
|
+
* ```typescript
|
|
1448
|
+
* import { workload } from '@enterprisestandard/react';
|
|
1449
|
+
*
|
|
1450
|
+
* const workloadAuth = workload({
|
|
1451
|
+
* token_url: 'https://auth.example.com/oauth/token',
|
|
1452
|
+
* jwks_uri: 'https://auth.example.com/.well-known/jwks.json',
|
|
1453
|
+
* workload_id: 'spiffe://trust-domain/ns/service',
|
|
1454
|
+
* audience: 'https://auth.example.com/oauth/token',
|
|
1455
|
+
* private_key: '-----BEGIN PRIVATE KEY-----...',
|
|
1456
|
+
* algorithm: 'RS256',
|
|
1457
|
+
* });
|
|
1458
|
+
*
|
|
1459
|
+
* // Get access token
|
|
1460
|
+
* const token = await workloadAuth.getToken('api:read api:write');
|
|
1461
|
+
* ```
|
|
1462
|
+
*/
|
|
1463
|
+
declare function workload(config?: WorkloadConfig): Workload;
|
|
1464
|
+
|
|
1465
|
+
/**
|
|
1466
|
+
* SCIM Error response structure
|
|
1467
|
+
*/
|
|
1468
|
+
interface ScimError {
|
|
1469
|
+
schemas: string[];
|
|
1470
|
+
status: string;
|
|
1471
|
+
scimType?: string;
|
|
1472
|
+
detail?: string;
|
|
1473
|
+
}
|
|
1474
|
+
/**
|
|
1475
|
+
* SCIM List Response for bulk operations
|
|
1476
|
+
*/
|
|
1477
|
+
interface ScimListResponse<T> {
|
|
1478
|
+
schemas: string[];
|
|
1479
|
+
totalResults: number;
|
|
1480
|
+
startIndex?: number;
|
|
1481
|
+
itemsPerPage?: number;
|
|
1482
|
+
Resources: T[];
|
|
1483
|
+
}
|
|
1484
|
+
/**
|
|
1485
|
+
* Result of a SCIM operation
|
|
1486
|
+
*/
|
|
1487
|
+
interface ScimResult<T> {
|
|
1488
|
+
success: boolean;
|
|
1489
|
+
data?: T;
|
|
1490
|
+
error?: ScimError;
|
|
1491
|
+
status: number;
|
|
1492
|
+
}
|
|
1493
|
+
/**
|
|
1494
|
+
* Handler configuration for IAM
|
|
1495
|
+
*/
|
|
1496
|
+
interface IAMHandlerConfig {
|
|
1497
|
+
/**
|
|
1498
|
+
* Base path for the SCIM Users endpoints (e.g., '/api/iam/Users')
|
|
1499
|
+
*/
|
|
1500
|
+
usersUrl?: string;
|
|
1501
|
+
/**
|
|
1502
|
+
* Base path for the SCIM Groups endpoints (e.g., '/api/iam/Groups')
|
|
1503
|
+
*/
|
|
1504
|
+
groupsUrl?: string;
|
|
1505
|
+
}
|
|
1506
|
+
/**
|
|
1507
|
+
* IAM configuration
|
|
1508
|
+
*
|
|
1509
|
+
* - If `url` is provided, groups_outbound is enabled (app calls external IAM)
|
|
1510
|
+
* - If `group_store` is provided, groups_inbound is enabled (external IAM calls app)
|
|
1511
|
+
* - If `user_store` is provided, users_inbound is enabled (external IAM calls app)
|
|
1512
|
+
*/
|
|
1513
|
+
type IAMConfig = {
|
|
1514
|
+
/**
|
|
1515
|
+
* Base URL of the external SCIM endpoint (e.g., https://sailpoint.example.com/scim/v2)
|
|
1516
|
+
* If provided, enables outbound SCIM operations (app -> external IAM)
|
|
1517
|
+
*/
|
|
1518
|
+
url?: string;
|
|
1519
|
+
/**
|
|
1520
|
+
* Store for inbound user provisioning from external IAM providers.
|
|
1521
|
+
* When configured, the app can receive user CRUD operations via SCIM.
|
|
1522
|
+
*/
|
|
1523
|
+
user_store?: UserStore;
|
|
1524
|
+
/**
|
|
1525
|
+
* Store for inbound group provisioning from external IAM providers.
|
|
1526
|
+
* When configured, enables groups_inbound (external IAM -> app).
|
|
1527
|
+
*/
|
|
1528
|
+
group_store?: GroupStore;
|
|
1529
|
+
/**
|
|
1530
|
+
* Optional handler defaults. These are merged with per-call overrides in
|
|
1531
|
+
* `iam.handler`, with per-call values taking precedence.
|
|
1532
|
+
*/
|
|
1533
|
+
usersUrl?: string;
|
|
1534
|
+
groupsUrl?: string;
|
|
1535
|
+
};
|
|
1536
|
+
/**
|
|
1537
|
+
* Options for creating a group
|
|
1538
|
+
*/
|
|
1539
|
+
interface CreateGroupOptions {
|
|
1540
|
+
/**
|
|
1541
|
+
* External identifier for the group
|
|
1542
|
+
*/
|
|
1543
|
+
externalId?: string;
|
|
1544
|
+
/**
|
|
1545
|
+
* Initial members to add to the group
|
|
1546
|
+
*/
|
|
1547
|
+
members?: GroupMember[];
|
|
1548
|
+
/**
|
|
1549
|
+
* Custom validation schema for the response
|
|
1550
|
+
*/
|
|
1551
|
+
validation?: StandardSchemaV1<unknown, GroupResource>;
|
|
1552
|
+
}
|
|
1553
|
+
/**
|
|
1554
|
+
* Options for creating a user
|
|
1555
|
+
*/
|
|
1556
|
+
interface CreateUserOptions {
|
|
1557
|
+
/**
|
|
1558
|
+
* Custom validation schema for the response
|
|
1559
|
+
*/
|
|
1560
|
+
validation?: StandardSchemaV1<unknown, User$1>;
|
|
1561
|
+
}
|
|
1562
|
+
/**
|
|
1563
|
+
* Handler configuration for groups_inbound
|
|
1564
|
+
*/
|
|
1565
|
+
interface GroupsInboundHandlerConfig {
|
|
1566
|
+
/**
|
|
1567
|
+
* Base path for the SCIM Groups endpoints (e.g., '/api/iam/Groups')
|
|
1568
|
+
*/
|
|
1569
|
+
basePath?: string;
|
|
1570
|
+
}
|
|
1571
|
+
/**
|
|
1572
|
+
* Handler configuration for users_inbound
|
|
1573
|
+
*/
|
|
1574
|
+
interface UsersInboundHandlerConfig {
|
|
1575
|
+
/**
|
|
1576
|
+
* Base path for the SCIM Users endpoints (e.g., '/api/iam/Users')
|
|
1577
|
+
*/
|
|
1578
|
+
basePath?: string;
|
|
1579
|
+
}
|
|
1580
|
+
/**
|
|
1581
|
+
* Groups Outbound extension - for creating groups in external IAM providers.
|
|
1582
|
+
* Enabled when `url` is configured in IAMConfig.
|
|
1583
|
+
*/
|
|
1584
|
+
type IAMGroupsOutbound = {
|
|
1585
|
+
/**
|
|
1586
|
+
* Create a new group in the external IAM provider
|
|
1587
|
+
* @param displayName - The display name for the group
|
|
1588
|
+
* @param options - Optional configuration for the group creation
|
|
1589
|
+
* @returns The created group resource from the provider
|
|
1590
|
+
*/
|
|
1591
|
+
createGroup: (displayName: string, options?: CreateGroupOptions) => Promise<ScimResult<GroupResource>>;
|
|
1592
|
+
};
|
|
1593
|
+
/**
|
|
1594
|
+
* Groups Inbound extension - for receiving group provisioning from external IAM providers.
|
|
1595
|
+
* Enabled when `group_store` is configured in IAMConfig.
|
|
1596
|
+
*/
|
|
1597
|
+
type IAMGroupsInbound = {
|
|
1598
|
+
/**
|
|
1599
|
+
* Handle inbound SCIM requests for group management.
|
|
1600
|
+
* Routes: GET/POST /Groups, GET/PUT/PATCH/DELETE /Groups/:id
|
|
1601
|
+
*/
|
|
1602
|
+
handler: (request: Request, config?: GroupsInboundHandlerConfig) => Promise<Response>;
|
|
1603
|
+
};
|
|
1604
|
+
/**
|
|
1605
|
+
* Users Inbound extension - for receiving user provisioning from external IAM providers.
|
|
1606
|
+
* Enabled when `user_store` is configured in IAMConfig.
|
|
1607
|
+
*/
|
|
1608
|
+
type IAMUsersInbound = {
|
|
1609
|
+
/**
|
|
1610
|
+
* Handle inbound SCIM requests for user management.
|
|
1611
|
+
* Routes: GET/POST /Users, GET/PUT/PATCH/DELETE /Users/:id
|
|
1612
|
+
*/
|
|
1613
|
+
handler: (request: Request, config?: UsersInboundHandlerConfig) => Promise<Response>;
|
|
1614
|
+
};
|
|
1615
|
+
/**
|
|
1616
|
+
* Core IAM service interface.
|
|
1617
|
+
*
|
|
1618
|
+
* - Core functions are user-related (outbound to external IAM)
|
|
1619
|
+
* - `groups_outbound` is available when `url` is configured
|
|
1620
|
+
* - `groups_inbound` is available when `group_store` is configured
|
|
1621
|
+
* - `users_inbound` is available when `user_store` is configured
|
|
1622
|
+
*/
|
|
1623
|
+
type IAM = IAMConfig & {
|
|
1624
|
+
/**
|
|
1625
|
+
* Create a new user/account in the external IAM provider
|
|
1626
|
+
* Only available when `url` is configured.
|
|
1627
|
+
*/
|
|
1628
|
+
createUser?: (user: User$1, options?: CreateUserOptions) => Promise<ScimResult<User$1>>;
|
|
1629
|
+
/**
|
|
1630
|
+
* Get the configured external SCIM base URL
|
|
1631
|
+
*/
|
|
1632
|
+
getBaseUrl: () => string | undefined;
|
|
1633
|
+
/**
|
|
1634
|
+
* Groups Outbound extension - create groups in external IAM provider.
|
|
1635
|
+
* Available when `url` is configured in IAMConfig.
|
|
1636
|
+
*/
|
|
1637
|
+
groups_outbound?: IAMGroupsOutbound;
|
|
1638
|
+
/**
|
|
1639
|
+
* Groups Inbound extension - receive group provisioning from external IAM.
|
|
1640
|
+
* Available when `group_store` is configured in IAMConfig.
|
|
1641
|
+
*/
|
|
1642
|
+
groups_inbound?: IAMGroupsInbound;
|
|
1643
|
+
/**
|
|
1644
|
+
* Users Inbound extension - receive user provisioning from external IAM.
|
|
1645
|
+
* Available when `user_store` is configured in IAMConfig.
|
|
1646
|
+
*/
|
|
1647
|
+
users_inbound?: IAMUsersInbound;
|
|
1648
|
+
/**
|
|
1649
|
+
* Framework-agnostic request handler for IAM endpoints.
|
|
1650
|
+
* Routes to users_inbound or groups_inbound handlers based on the request path.
|
|
1651
|
+
*/
|
|
1652
|
+
handler: (request: Request, config?: IAMHandlerConfig) => Promise<Response>;
|
|
1653
|
+
};
|
|
1654
|
+
/**
|
|
1655
|
+
* Creates an IAM service instance.
|
|
1656
|
+
*
|
|
1657
|
+
* - If `url` is configured, enables outbound SCIM operations to external IAM
|
|
1658
|
+
* - If `group_store` is configured, enables inbound SCIM operations from external IAM
|
|
1659
|
+
*
|
|
1660
|
+
* @param config - IAM configuration
|
|
1661
|
+
* @param workload - Workload instance for authentication
|
|
1662
|
+
* @returns IAM service instance
|
|
1663
|
+
*/
|
|
1664
|
+
declare function iam(config: IAMConfig, workload: Workload): IAM;
|
|
1665
|
+
|
|
1666
|
+
/**
|
|
1667
|
+
* Session management for tracking user sessions and enabling backchannel logout.
|
|
1668
|
+
*
|
|
1669
|
+
* Session stores are optional - the package works with JWT cookies alone.
|
|
1670
|
+
* Sessions are only required for backchannel logout functionality.
|
|
1671
|
+
*
|
|
1672
|
+
* ## Session Validation Strategies
|
|
1673
|
+
*
|
|
1674
|
+
* When using a session store, you can configure when sessions are validated:
|
|
1675
|
+
*
|
|
1676
|
+
* ### 'always' (default)
|
|
1677
|
+
* Validates session on every authenticated request.
|
|
1678
|
+
* - **Security**: Maximum - immediate session revocation
|
|
1679
|
+
* - **Performance**: InMemory ~0.00005ms, Redis ~1-2ms per request
|
|
1680
|
+
* - **Backchannel Logout**: Takes effect immediately
|
|
1681
|
+
* - **Use when**: Security is paramount, using InMemory or Redis backend
|
|
1682
|
+
*
|
|
1683
|
+
* ### 'refresh-only'
|
|
1684
|
+
* Validates session only during token refresh (typically every 5-15 minutes).
|
|
1685
|
+
* - **Security**: Good - 5-15 minute revocation window
|
|
1686
|
+
* - **Performance**: 99% reduction in session lookups
|
|
1687
|
+
* - **Backchannel Logout**: Takes effect within token TTL (5-15 min)
|
|
1688
|
+
* - **Use when**: Performance is critical AND delayed revocation is acceptable
|
|
1689
|
+
* - **WARNING**: Compromised sessions remain valid until next refresh
|
|
1690
|
+
*
|
|
1691
|
+
* ### 'disabled'
|
|
1692
|
+
* Never validates sessions against the store.
|
|
1693
|
+
* - **Security**: None - backchannel logout doesn't work
|
|
1694
|
+
* - **Performance**: No overhead
|
|
1695
|
+
* - **Use when**: Cookie-only mode without session store
|
|
1696
|
+
* - **WARNING**: Do not use with session_store configured
|
|
1697
|
+
*
|
|
1698
|
+
* ## Performance Characteristics
|
|
1699
|
+
*
|
|
1700
|
+
* | Backend | Lookup Time | Impact on Request | Recommendation |
|
|
1701
|
+
* |--------------|-------------|-------------------|------------------------|
|
|
1702
|
+
* | InMemory | <0.00005ms | Negligible | Use 'always' |
|
|
1703
|
+
* | Redis | 1-2ms | 2-4% increase | Use 'always' or test |
|
|
1704
|
+
* | Database | 5-20ms | 10-40% increase | Use Redis cache layer |
|
|
1705
|
+
*
|
|
1706
|
+
* ## Example Usage
|
|
1707
|
+
*
|
|
1708
|
+
* ```typescript
|
|
1709
|
+
* import { sso, InMemorySessionStore } from '@enterprisestandard/react/server';
|
|
1710
|
+
*
|
|
1711
|
+
* // Maximum security (default)
|
|
1712
|
+
* const secure = sso({
|
|
1713
|
+
* // ... other config
|
|
1714
|
+
* session_store: new InMemorySessionStore(),
|
|
1715
|
+
* session_validation: 'always', // Immediate revocation
|
|
1716
|
+
* });
|
|
1717
|
+
*
|
|
1718
|
+
* // High performance
|
|
1719
|
+
* const fast = sso({
|
|
1720
|
+
* // ... other config
|
|
1721
|
+
* session_store: new InMemorySessionStore(),
|
|
1722
|
+
* session_validation: {
|
|
1723
|
+
* strategy: 'refresh-only' // 5-15 min revocation delay
|
|
1724
|
+
* }
|
|
1725
|
+
* });
|
|
1726
|
+
* ```
|
|
1727
|
+
*/
|
|
1728
|
+
/**
|
|
1729
|
+
* Core session data tracked for each authenticated user session.
|
|
1730
|
+
*
|
|
1731
|
+
* @template TExtended - Type-safe custom data that consumers can add to sessions
|
|
1732
|
+
*/
|
|
1733
|
+
type Session<TExtended = {}> = {
|
|
1734
|
+
/**
|
|
1735
|
+
* Session ID from the Identity Provider (from `sid` claim in ID token).
|
|
1736
|
+
* This is the unique identifier for the session.
|
|
1737
|
+
*/
|
|
1738
|
+
sid: string;
|
|
1739
|
+
/**
|
|
1740
|
+
* Subject identifier (user ID) from the Identity Provider.
|
|
1741
|
+
* From the `sub` claim in the ID token.
|
|
1742
|
+
*/
|
|
1743
|
+
sub: string;
|
|
1744
|
+
/**
|
|
1745
|
+
* Timestamp when the session was created.
|
|
1746
|
+
*/
|
|
1747
|
+
createdAt: Date;
|
|
1748
|
+
/**
|
|
1749
|
+
* Timestamp of the last activity in this session.
|
|
1750
|
+
* Can be updated to track session activity.
|
|
1751
|
+
*/
|
|
1752
|
+
lastActivityAt: Date;
|
|
1753
|
+
/**
|
|
1754
|
+
* Allow consumers to add runtime data to sessions.
|
|
1755
|
+
*/
|
|
1756
|
+
[key: string]: unknown;
|
|
1757
|
+
} & TExtended;
|
|
1758
|
+
/**
|
|
1759
|
+
* Abstract interface for session storage backends.
|
|
1760
|
+
*
|
|
1761
|
+
* Consumers can implement this interface to use different storage backends:
|
|
1762
|
+
* - Redis
|
|
1763
|
+
* - Database (PostgreSQL, MySQL, etc.)
|
|
1764
|
+
* - Distributed cache
|
|
1765
|
+
* - Custom solutions
|
|
1766
|
+
*
|
|
1767
|
+
* @template TExtended - Type-safe custom data that consumers can add to sessions
|
|
1768
|
+
*
|
|
1769
|
+
* @example
|
|
1770
|
+
* ```typescript
|
|
1771
|
+
* // Custom session data
|
|
1772
|
+
* type MySessionData = {
|
|
1773
|
+
* ipAddress: string;
|
|
1774
|
+
* userAgent: string;
|
|
1775
|
+
* };
|
|
1776
|
+
*
|
|
1777
|
+
* // Implement custom store
|
|
1778
|
+
* class RedisSessionStore implements SessionStore<MySessionData> {
|
|
1779
|
+
* async create(session: Session<MySessionData>): Promise<void> {
|
|
1780
|
+
* await redis.set(`session:${session.sid}`, JSON.stringify(session));
|
|
1781
|
+
* }
|
|
1782
|
+
* // ... other methods
|
|
1783
|
+
* }
|
|
1784
|
+
* ```
|
|
1785
|
+
*/
|
|
1786
|
+
interface SessionStore<TExtended = {}> {
|
|
1787
|
+
/**
|
|
1788
|
+
* Create a new session in the store.
|
|
1789
|
+
*
|
|
1790
|
+
* @param session - The session data to store
|
|
1791
|
+
* @throws Error if session with same sid already exists
|
|
1792
|
+
*/
|
|
1793
|
+
create(session: Session<TExtended>): Promise<void>;
|
|
1794
|
+
/**
|
|
1795
|
+
* Retrieve a session by its IdP session ID (sid).
|
|
1796
|
+
*
|
|
1797
|
+
* @param sid - The session.sid from the Identity Provider
|
|
1798
|
+
* @returns The session if found, null otherwise
|
|
1799
|
+
*/
|
|
1800
|
+
get(sid: string): Promise<Session<TExtended> | null>;
|
|
1801
|
+
/**
|
|
1802
|
+
* Update an existing session with partial data.
|
|
1803
|
+
*
|
|
1804
|
+
* Commonly used to update lastActivityAt or add custom fields.
|
|
1805
|
+
*
|
|
1806
|
+
* @param sid - The session.sid to update
|
|
1807
|
+
* @param data - Partial session data to merge
|
|
1808
|
+
* @throws Error if session not found
|
|
1809
|
+
*/
|
|
1810
|
+
update(sid: string, data: Partial<Session<TExtended>>): Promise<void>;
|
|
1811
|
+
/**
|
|
1812
|
+
* Delete a session by its IdP session ID (sid).
|
|
1813
|
+
*
|
|
1814
|
+
* Used for both normal logout and backchannel logout flows.
|
|
1815
|
+
*
|
|
1816
|
+
* @param sid - The session.sid to delete
|
|
1817
|
+
*/
|
|
1818
|
+
delete(sid: string): Promise<void>;
|
|
1819
|
+
}
|
|
1820
|
+
/**
|
|
1821
|
+
* In-memory session store implementation using Maps.
|
|
1822
|
+
*
|
|
1823
|
+
* Suitable for:
|
|
1824
|
+
* - Development and testing
|
|
1825
|
+
* - Single-server deployments
|
|
1826
|
+
* - Applications without high availability requirements
|
|
1827
|
+
*
|
|
1828
|
+
* NOT suitable for:
|
|
1829
|
+
* - Multi-server deployments (sessions not shared)
|
|
1830
|
+
* - High availability scenarios (sessions lost on restart)
|
|
1831
|
+
* - Production applications with distributed architecture
|
|
1832
|
+
*
|
|
1833
|
+
* For production, implement SessionStore with Redis or a database.
|
|
1834
|
+
*
|
|
1835
|
+
* @template TExtended - Type-safe custom data that consumers can add to sessions
|
|
1836
|
+
*/
|
|
1837
|
+
declare class InMemorySessionStore<TExtended = {}> implements SessionStore<TExtended> {
|
|
1838
|
+
private sessions;
|
|
1839
|
+
create(session: Session<TExtended>): Promise<void>;
|
|
1840
|
+
get(sid: string): Promise<Session<TExtended> | null>;
|
|
1841
|
+
update(sid: string, data: Partial<Session<TExtended>>): Promise<void>;
|
|
1842
|
+
delete(sid: string): Promise<void>;
|
|
1843
|
+
}
|
|
1844
|
+
|
|
1845
|
+
type SSOConfig<TSessionData = {}, TUserData = {}> = {
|
|
1846
|
+
authority?: string;
|
|
1847
|
+
token_url?: string;
|
|
1848
|
+
authorization_url?: string;
|
|
1849
|
+
client_id?: string;
|
|
1850
|
+
client_secret?: string;
|
|
1851
|
+
redirect_uri?: string;
|
|
1852
|
+
response_type?: 'code';
|
|
1853
|
+
scope?: string;
|
|
1854
|
+
silent_redirect_uri?: string;
|
|
1855
|
+
jwks_uri?: string;
|
|
1856
|
+
cookies_prefix?: string;
|
|
1857
|
+
cookies_path?: string;
|
|
1858
|
+
cookies_secure?: boolean;
|
|
1859
|
+
cookies_same_site?: 'Strict' | 'Lax';
|
|
1860
|
+
end_session_endpoint?: string;
|
|
1861
|
+
revocation_endpoint?: string;
|
|
1862
|
+
session_store?: SessionStore<TSessionData>;
|
|
1863
|
+
/**
|
|
1864
|
+
* Optional handler defaults. These are merged with per-call overrides in
|
|
1865
|
+
* `sso.handler`, with per-call values taking precedence.
|
|
1866
|
+
*/
|
|
1867
|
+
loginUrl?: string;
|
|
1868
|
+
userUrl?: string;
|
|
1869
|
+
errorUrl?: string;
|
|
1870
|
+
landingUrl?: string;
|
|
1871
|
+
tokenUrl?: string;
|
|
1872
|
+
refreshUrl?: string;
|
|
1873
|
+
jwksUrl?: string;
|
|
1874
|
+
logoutUrl?: string;
|
|
1875
|
+
logoutBackChannelUrl?: string;
|
|
1876
|
+
validation?: {
|
|
1877
|
+
callbackParams?: StandardSchemaV1<unknown, OidcCallbackParams>;
|
|
1878
|
+
idTokenClaims?: StandardSchemaV1<unknown, IdTokenClaims>;
|
|
1879
|
+
tokenResponse?: StandardSchemaV1<unknown, TokenResponse>;
|
|
1880
|
+
};
|
|
1881
|
+
/**
|
|
1882
|
+
* Optional user store for persisting user profiles from SSO authentication.
|
|
1883
|
+
* When configured, users are automatically stored/updated on each login.
|
|
1884
|
+
*/
|
|
1885
|
+
user_store?: UserStore<TUserData>;
|
|
1886
|
+
/**
|
|
1887
|
+
* Enable Just-In-Time (JIT) user provisioning.
|
|
1888
|
+
* When enabled, new users are automatically created in the user_store on their first login.
|
|
1889
|
+
* When disabled (default), only existing users in the user_store are updated on login.
|
|
1890
|
+
* Requires user_store to be configured.
|
|
1891
|
+
* @default false
|
|
1892
|
+
*/
|
|
1893
|
+
enable_jit_user_provisioning?: boolean;
|
|
1894
|
+
};
|
|
1895
|
+
type SSOConfigWithDefaults<TSessionData = {}, TUserData = {}> = SSOConfig<TSessionData, TUserData> & {
|
|
1896
|
+
authority: string;
|
|
1897
|
+
token_url: string;
|
|
1898
|
+
authorization_url: string;
|
|
1899
|
+
client_id: string;
|
|
1900
|
+
redirect_uri: string;
|
|
1901
|
+
response_type: 'code';
|
|
1902
|
+
scope: string;
|
|
1903
|
+
cookies_secure: boolean;
|
|
1904
|
+
cookies_same_site: string;
|
|
1905
|
+
cookies_prefix: string;
|
|
1906
|
+
cookies_path: string;
|
|
1907
|
+
};
|
|
1908
|
+
type ESConfig$1 = {
|
|
1909
|
+
es?: EnterpriseStandard;
|
|
1910
|
+
};
|
|
1911
|
+
type LoginConfig = {
|
|
1912
|
+
landingUrl: string;
|
|
1913
|
+
errorUrl?: string;
|
|
1914
|
+
} & ESConfig$1;
|
|
1915
|
+
type SSOHandlerConfig = {
|
|
1916
|
+
loginUrl?: string;
|
|
1917
|
+
userUrl?: string;
|
|
1918
|
+
errorUrl?: string;
|
|
1919
|
+
landingUrl?: string;
|
|
1920
|
+
tokenUrl?: string;
|
|
1921
|
+
refreshUrl?: string;
|
|
1922
|
+
jwksUrl?: string;
|
|
1923
|
+
logoutUrl?: string;
|
|
1924
|
+
logoutBackChannelUrl?: string;
|
|
1925
|
+
validation?: {
|
|
1926
|
+
callbackParams?: StandardSchemaV1<unknown, OidcCallbackParams>;
|
|
1927
|
+
idTokenClaims?: StandardSchemaV1<unknown, IdTokenClaims>;
|
|
1928
|
+
tokenResponse?: StandardSchemaV1<unknown, TokenResponse>;
|
|
1929
|
+
};
|
|
1930
|
+
} & ESConfig$1;
|
|
1931
|
+
type SSO<TSessionData = {}, TUserData = {}> = SSOConfigWithDefaults<TSessionData, TUserData> & {
|
|
1932
|
+
getUser: (request: Request) => Promise<User | undefined>;
|
|
1933
|
+
getRequiredUser: (request: Request) => Promise<User>;
|
|
1934
|
+
getJwt: (request: Request) => Promise<string | undefined>;
|
|
1935
|
+
initiateLogin: (config: LoginConfig, requestUrl?: string) => Promise<Response>;
|
|
1936
|
+
logout: (request: Request, config?: LoginConfig) => Promise<Response>;
|
|
1937
|
+
callbackHandler: (request: Request) => Promise<Response>;
|
|
1938
|
+
handler: (request: Request, es?: EnterpriseStandard) => Promise<Response>;
|
|
1939
|
+
};
|
|
1940
|
+
declare function sso<TSessionData = {}, TUserData = {}>(config?: SSOConfig<TSessionData, TUserData>): SSO<TSessionData, TUserData>;
|
|
1941
|
+
|
|
1942
|
+
type Secret<T> = {
|
|
1943
|
+
data: T;
|
|
1944
|
+
metadata: MetaData;
|
|
1945
|
+
};
|
|
1946
|
+
type MetaData = {
|
|
1947
|
+
created_time: string;
|
|
1948
|
+
deletion_time: string;
|
|
1949
|
+
destroyed: boolean;
|
|
1950
|
+
version: number;
|
|
1951
|
+
};
|
|
1952
|
+
type Vault = {
|
|
1953
|
+
url: string;
|
|
1954
|
+
getFullSecret: <T>(path: string, token: string) => Promise<Secret<T>>;
|
|
1955
|
+
getSecret: <T>(path: string, token: string) => Promise<T>;
|
|
1956
|
+
};
|
|
1957
|
+
declare function vault(url: string): Vault;
|
|
1958
|
+
|
|
1959
|
+
/**
|
|
1960
|
+
* Tenant Management SDK
|
|
1961
|
+
*
|
|
1962
|
+
* Provides helper functions for applications to implement tenant creation endpoints
|
|
1963
|
+
* that ESVS can test. Supports both synchronous (201) and asynchronous (202)
|
|
1964
|
+
* tenant creation with webhook-based status updates.
|
|
1965
|
+
*/
|
|
1966
|
+
/**
|
|
1967
|
+
* Environment type for tenant creation
|
|
1968
|
+
*/
|
|
1969
|
+
type EnvironmentType = 'POC' | 'DEV' | 'QA' | 'PROD';
|
|
1970
|
+
/**
|
|
1971
|
+
* Status of tenant creation process
|
|
1972
|
+
*/
|
|
1973
|
+
type TenantStatus = 'pending' | 'processing' | 'completed' | 'failed';
|
|
1974
|
+
/**
|
|
1975
|
+
* Request payload from ESVS for creating a tenant
|
|
1976
|
+
*/
|
|
1977
|
+
interface CreateTenantRequest {
|
|
1978
|
+
/**
|
|
1979
|
+
* Required app identifier to use when initializing EnterpriseStandard for this tenant.
|
|
1980
|
+
* This is the primary identifier for tenant management. A company can have multiple
|
|
1981
|
+
* applications (e.g., one instance on the east coast, one on the west coast).
|
|
1982
|
+
*/
|
|
1983
|
+
appId: string;
|
|
1984
|
+
/**
|
|
1985
|
+
* Company ID (used for reporting purposes only, not for tenant identification)
|
|
1986
|
+
*/
|
|
1987
|
+
companyId: string;
|
|
1988
|
+
/**
|
|
1989
|
+
* Company Name
|
|
1990
|
+
*/
|
|
1991
|
+
companyName: string;
|
|
1992
|
+
/**
|
|
1993
|
+
* Environment Type (POC, DEV, QA, PROD)
|
|
1994
|
+
*/
|
|
1995
|
+
environmentType: EnvironmentType;
|
|
1996
|
+
/**
|
|
1997
|
+
* Email (The email or distribution list used to communicate to the team)
|
|
1998
|
+
*/
|
|
1999
|
+
email: string;
|
|
2000
|
+
/**
|
|
2001
|
+
* Webhook URL where the application can send updates around the creation of the tenant
|
|
2002
|
+
*/
|
|
2003
|
+
webhookUrl: string;
|
|
2004
|
+
}
|
|
2005
|
+
/**
|
|
2006
|
+
* Response payload for tenant creation
|
|
2007
|
+
*/
|
|
2008
|
+
interface CreateTenantResponse {
|
|
2009
|
+
/**
|
|
2010
|
+
* URL that the tenant will be available at
|
|
2011
|
+
*/
|
|
2012
|
+
tenantUrl: string;
|
|
2013
|
+
/**
|
|
2014
|
+
* Current status of tenant creation
|
|
2015
|
+
*/
|
|
2016
|
+
status: TenantStatus;
|
|
2017
|
+
}
|
|
2018
|
+
/**
|
|
2019
|
+
* Payload sent to webhook URL for status updates
|
|
2020
|
+
*/
|
|
2021
|
+
interface TenantWebhookPayload {
|
|
2022
|
+
/**
|
|
2023
|
+
* Company ID
|
|
2024
|
+
*/
|
|
2025
|
+
companyId: string;
|
|
2026
|
+
/**
|
|
2027
|
+
* Current status of tenant creation
|
|
2028
|
+
*/
|
|
2029
|
+
status: TenantStatus;
|
|
2030
|
+
/**
|
|
2031
|
+
* URL that the tenant will be available at (provided once creation completes)
|
|
2032
|
+
*/
|
|
2033
|
+
tenantUrl?: string;
|
|
2034
|
+
/**
|
|
2035
|
+
* Error message (only present if status is "failed")
|
|
2036
|
+
*/
|
|
2037
|
+
error?: string;
|
|
2038
|
+
}
|
|
2039
|
+
/**
|
|
2040
|
+
* Error thrown when tenant request validation fails
|
|
2041
|
+
*/
|
|
2042
|
+
declare class TenantRequestError extends Error {
|
|
2043
|
+
constructor(message: string);
|
|
2044
|
+
}
|
|
2045
|
+
/**
|
|
2046
|
+
* Serializes an ESConfig or EnterpriseStandard instance to a JSON-serializable format
|
|
2047
|
+
* by removing non-serializable properties like stores, validators, and functions.
|
|
2048
|
+
*
|
|
2049
|
+
* Since EnterpriseStandard now extends ESConfig, the config (including handler URLs)
|
|
2050
|
+
* is accessible directly from the instance.
|
|
2051
|
+
*
|
|
2052
|
+
* @param configOrES - The ESConfig object or EnterpriseStandard instance to serialize
|
|
2053
|
+
* @returns A JSON-serializable version of the config
|
|
2054
|
+
*/
|
|
2055
|
+
declare function serializeESConfig(configOrES: any): any;
|
|
2056
|
+
/**
|
|
2057
|
+
* Parse and validate a tenant creation request from an HTTP request.
|
|
2058
|
+
*
|
|
2059
|
+
* @param request - The HTTP request containing the tenant creation data
|
|
2060
|
+
* @returns The validated tenant creation request
|
|
2061
|
+
* @throws {TenantRequestError} If the request is invalid or missing required fields
|
|
2062
|
+
*
|
|
2063
|
+
* @example
|
|
2064
|
+
* ```typescript
|
|
2065
|
+
* app.post('/api/tenant', async (c) => {
|
|
2066
|
+
* try {
|
|
2067
|
+
* const tenantRequest = await parseTenantRequest(c.req.raw);
|
|
2068
|
+
* // Create tenant...
|
|
2069
|
+
* } catch (error) {
|
|
2070
|
+
* if (error instanceof TenantRequestError) {
|
|
2071
|
+
* return c.json({ error: error.message }, 400);
|
|
2072
|
+
* }
|
|
2073
|
+
* throw error;
|
|
2074
|
+
* }
|
|
2075
|
+
* });
|
|
2076
|
+
* ```
|
|
2077
|
+
*/
|
|
2078
|
+
declare function parseTenantRequest(request: Request): Promise<CreateTenantRequest>;
|
|
2079
|
+
/**
|
|
2080
|
+
* Send a webhook update to ESVS with tenant creation status.
|
|
2081
|
+
*
|
|
2082
|
+
* @param webhookUrl - The webhook URL provided in the tenant creation request
|
|
2083
|
+
* @param payload - The webhook payload with status and tenant information
|
|
2084
|
+
* @throws Never throws - errors are logged but not propagated to avoid breaking tenant creation
|
|
2085
|
+
*
|
|
2086
|
+
* @example
|
|
2087
|
+
* ```typescript
|
|
2088
|
+
* // Send initial status
|
|
2089
|
+
* await sendTenantWebhook(tenantRequest.webhookUrl, {
|
|
2090
|
+
* companyId: tenantRequest.companyId,
|
|
2091
|
+
* status: 'processing',
|
|
2092
|
+
* });
|
|
2093
|
+
*
|
|
2094
|
+
* // Send completion status
|
|
2095
|
+
* await sendTenantWebhook(tenantRequest.webhookUrl, {
|
|
2096
|
+
* companyId: tenantRequest.companyId,
|
|
2097
|
+
* status: 'completed',
|
|
2098
|
+
* tenantUrl: 'https://app.example.com/tenants/tenant-123',
|
|
2099
|
+
* });
|
|
2100
|
+
* ```
|
|
2101
|
+
*/
|
|
2102
|
+
declare function sendTenantWebhook(webhookUrl: string, payload: TenantWebhookPayload): Promise<void>;
|
|
2103
|
+
/**
|
|
2104
|
+
* Stored tenant data with required appId and tracking metadata.
|
|
2105
|
+
*
|
|
2106
|
+
* @template TExtended - Type-safe custom data that consumers can add to tenants
|
|
2107
|
+
*/
|
|
2108
|
+
type StoredTenant<TExtended = {}> = {
|
|
2109
|
+
/**
|
|
2110
|
+
* Required app identifier used to initialize EnterpriseStandard for this tenant.
|
|
2111
|
+
* This is the primary key for tenant storage. A company can have multiple
|
|
2112
|
+
* applications (e.g., one instance on the east coast, one on the west coast).
|
|
2113
|
+
*/
|
|
2114
|
+
appId: string;
|
|
2115
|
+
/**
|
|
2116
|
+
* Company ID (used for reporting purposes only, not for tenant identification)
|
|
2117
|
+
*/
|
|
2118
|
+
companyId: string;
|
|
2119
|
+
/**
|
|
2120
|
+
* Company Name
|
|
2121
|
+
*/
|
|
2122
|
+
companyName: string;
|
|
2123
|
+
/**
|
|
2124
|
+
* Environment Type (POC, DEV, QA, PROD)
|
|
2125
|
+
*/
|
|
2126
|
+
environmentType: EnvironmentType;
|
|
2127
|
+
/**
|
|
2128
|
+
* Email (The email or distribution list used to communicate to the team)
|
|
2129
|
+
*/
|
|
2130
|
+
email: string;
|
|
2131
|
+
/**
|
|
2132
|
+
* Webhook URL where the application can send updates around the creation of the tenant
|
|
2133
|
+
*/
|
|
2134
|
+
webhookUrl: string;
|
|
2135
|
+
/**
|
|
2136
|
+
* URL that the tenant will be available at
|
|
2137
|
+
*/
|
|
2138
|
+
tenantUrl?: string;
|
|
2139
|
+
/**
|
|
2140
|
+
* Current status of tenant creation
|
|
2141
|
+
*/
|
|
2142
|
+
status: TenantStatus;
|
|
2143
|
+
/**
|
|
2144
|
+
* Error message (only present if status is "failed")
|
|
2145
|
+
*/
|
|
2146
|
+
error?: string;
|
|
2147
|
+
/**
|
|
2148
|
+
* Timestamp when the tenant was first stored.
|
|
2149
|
+
*/
|
|
2150
|
+
createdAt: Date;
|
|
2151
|
+
/**
|
|
2152
|
+
* Timestamp when the tenant was last updated.
|
|
2153
|
+
*/
|
|
2154
|
+
updatedAt: Date;
|
|
2155
|
+
/**
|
|
2156
|
+
* Serialized Enterprise Standard configuration.
|
|
2157
|
+
* This is a JSON-serializable version of the ESConfig with non-serializable items excluded.
|
|
2158
|
+
*/
|
|
2159
|
+
config?: any;
|
|
2160
|
+
} & TExtended;
|
|
2161
|
+
/**
|
|
2162
|
+
* Abstract interface for tenant storage backends.
|
|
2163
|
+
*
|
|
2164
|
+
* Consumers can implement this interface to use different storage backends:
|
|
2165
|
+
* - In-memory (for development/testing)
|
|
2166
|
+
* - Redis (for production with fast lookups)
|
|
2167
|
+
* - Database (PostgreSQL, MySQL, etc.)
|
|
2168
|
+
*
|
|
2169
|
+
* @template TExtended - Type-safe custom data that consumers can add to tenants
|
|
2170
|
+
*/
|
|
2171
|
+
interface TenantStore<TExtended = {}> {
|
|
2172
|
+
/**
|
|
2173
|
+
* Retrieve a tenant by its app identifier.
|
|
2174
|
+
*
|
|
2175
|
+
* @param appId - The tenant's app identifier (primary key)
|
|
2176
|
+
* @returns The tenant if found, null otherwise
|
|
2177
|
+
*/
|
|
2178
|
+
get(appId: string): Promise<StoredTenant<TExtended> | null>;
|
|
2179
|
+
/**
|
|
2180
|
+
* Retrieve all tenants for a company ID.
|
|
2181
|
+
* Since a company can have multiple applications, this returns an array.
|
|
2182
|
+
*
|
|
2183
|
+
* @param companyId - The company ID (used for reporting, not primary identification)
|
|
2184
|
+
* @returns Array of tenants for the company, empty array if none found
|
|
2185
|
+
*/
|
|
2186
|
+
getByCompanyId(companyId: string): Promise<StoredTenant<TExtended>[]>;
|
|
2187
|
+
/**
|
|
2188
|
+
* List all tenants in the store.
|
|
2189
|
+
*
|
|
2190
|
+
* @returns Array of all stored tenants
|
|
2191
|
+
*/
|
|
2192
|
+
list(): Promise<StoredTenant<TExtended>[]>;
|
|
2193
|
+
/**
|
|
2194
|
+
* Create or update a tenant in the store.
|
|
2195
|
+
*
|
|
2196
|
+
* If a tenant with the same `appId` exists, it will be updated.
|
|
2197
|
+
* Otherwise, a new tenant will be created.
|
|
2198
|
+
*
|
|
2199
|
+
* @param tenant - The tenant data to store
|
|
2200
|
+
* @returns The stored tenant
|
|
2201
|
+
*/
|
|
2202
|
+
upsert(tenant: StoredTenant<TExtended>): Promise<StoredTenant<TExtended>>;
|
|
2203
|
+
/**
|
|
2204
|
+
* Delete a tenant by its app identifier.
|
|
2205
|
+
*
|
|
2206
|
+
* @param appId - The tenant's app identifier to delete
|
|
2207
|
+
*/
|
|
2208
|
+
delete(appId: string): Promise<void>;
|
|
2209
|
+
}
|
|
2210
|
+
/**
|
|
2211
|
+
* In-memory tenant store implementation using Maps.
|
|
2212
|
+
*
|
|
2213
|
+
* Suitable for:
|
|
2214
|
+
* - Development and testing
|
|
2215
|
+
* - Single-server deployments
|
|
2216
|
+
* - Applications without high availability requirements
|
|
2217
|
+
*
|
|
2218
|
+
* NOT suitable for:
|
|
2219
|
+
* - Multi-server deployments (tenants not shared)
|
|
2220
|
+
* - High availability scenarios (tenants lost on restart)
|
|
2221
|
+
* - Production applications with distributed architecture
|
|
2222
|
+
*
|
|
2223
|
+
* For production, implement TenantStore with Redis or a database.
|
|
2224
|
+
*
|
|
2225
|
+
* @template TExtended - Type-safe custom data that consumers can add to tenants
|
|
2226
|
+
*/
|
|
2227
|
+
declare class InMemoryTenantStore<TExtended = {}> implements TenantStore<TExtended> {
|
|
2228
|
+
/** Primary storage: appId -> tenant */
|
|
2229
|
+
private tenants;
|
|
2230
|
+
/** Secondary index: companyId -> Set of appIds (since one company can have multiple apps) */
|
|
2231
|
+
private companyIdIndex;
|
|
2232
|
+
get(appId: string): Promise<StoredTenant<TExtended> | null>;
|
|
2233
|
+
getByCompanyId(companyId: string): Promise<StoredTenant<TExtended>[]>;
|
|
2234
|
+
list(): Promise<StoredTenant<TExtended>[]>;
|
|
2235
|
+
upsert(tenant: StoredTenant<TExtended>): Promise<StoredTenant<TExtended>>;
|
|
2236
|
+
delete(appId: string): Promise<void>;
|
|
2237
|
+
}
|
|
2238
|
+
|
|
2239
|
+
/**
|
|
2240
|
+
* Get the workload identity from an incoming request.
|
|
2241
|
+
* Returns undefined if no valid workload token is present.
|
|
2242
|
+
*
|
|
2243
|
+
* @param request - Request with Authorization header
|
|
2244
|
+
* @param config - Optional EnterpriseStandard configuration
|
|
2245
|
+
* @returns WorkloadIdentity or undefined
|
|
2246
|
+
*
|
|
2247
|
+
* @example
|
|
2248
|
+
* ```typescript
|
|
2249
|
+
* import { getWorkload } from '@enterprisestandard/react';
|
|
2250
|
+
*
|
|
2251
|
+
* export async function handler(request: Request) {
|
|
2252
|
+
* const workload = await getWorkload(request);
|
|
2253
|
+
*
|
|
2254
|
+
* if (!workload) {
|
|
2255
|
+
* return new Response('Unauthorized', { status: 401 });
|
|
2256
|
+
* }
|
|
2257
|
+
*
|
|
2258
|
+
* console.log('Request from workload:', workload.workload_id);
|
|
2259
|
+
* // ... process authenticated request
|
|
2260
|
+
* }
|
|
2261
|
+
* ```
|
|
2262
|
+
*/
|
|
2263
|
+
declare function getWorkload(request: Request, es?: EnterpriseStandard): Promise<WorkloadIdentity | undefined>;
|
|
2264
|
+
/**
|
|
2265
|
+
* Get an access token for the configured workload identity.
|
|
2266
|
+
*
|
|
2267
|
+
* @param scope - Optional OAuth2 scopes (space-delimited)
|
|
2268
|
+
* @param config - Optional EnterpriseStandard configuration
|
|
2269
|
+
* @returns Access token string
|
|
2270
|
+
*
|
|
2271
|
+
* @example
|
|
2272
|
+
* ```typescript
|
|
2273
|
+
* import { getWorkloadToken } from '@enterprisestandard/react/server';
|
|
2274
|
+
*
|
|
2275
|
+
* // Get token for API calls
|
|
2276
|
+
* const token = await getWorkloadToken('api:read api:write');
|
|
2277
|
+
*
|
|
2278
|
+
* // Use in outbound requests
|
|
2279
|
+
* const response = await fetch('https://api.example.com/data', {
|
|
2280
|
+
* headers: { 'Authorization': `Bearer ${token}` },
|
|
2281
|
+
* });
|
|
2282
|
+
* ```
|
|
2283
|
+
*/
|
|
2284
|
+
declare function getWorkloadToken(scope?: string, es?: EnterpriseStandard): Promise<string>;
|
|
2285
|
+
/**
|
|
2286
|
+
* Validate a workload token from an incoming request.
|
|
2287
|
+
*
|
|
2288
|
+
* @param request - Request with Authorization header
|
|
2289
|
+
* @param config - Optional EnterpriseStandard configuration
|
|
2290
|
+
* @returns Token validation result
|
|
2291
|
+
*
|
|
2292
|
+
* @example
|
|
2293
|
+
* ```typescript
|
|
2294
|
+
* import { validateWorkloadToken } from '@enterprisestandard/react/server';
|
|
2295
|
+
*
|
|
2296
|
+
* export async function handler(request: Request) {
|
|
2297
|
+
* const result = await validateWorkloadToken(request);
|
|
2298
|
+
*
|
|
2299
|
+
* if (!result.valid) {
|
|
2300
|
+
* return new Response(
|
|
2301
|
+
* JSON.stringify({ error: result.error }),
|
|
2302
|
+
* { status: 401 }
|
|
2303
|
+
* );
|
|
2304
|
+
* }
|
|
2305
|
+
*
|
|
2306
|
+
* const workloadId = result.claims?.iss;
|
|
2307
|
+
* // ... process authenticated request
|
|
2308
|
+
* }
|
|
2309
|
+
* ```
|
|
2310
|
+
*/
|
|
2311
|
+
declare function validateWorkloadToken(request: Request, es?: EnterpriseStandard): Promise<TokenValidationResult>;
|
|
2312
|
+
/**
|
|
2313
|
+
* Revoke a workload access token.
|
|
2314
|
+
*
|
|
2315
|
+
* @param token - The access token to revoke
|
|
2316
|
+
* @param config - Optional EnterpriseStandard configuration
|
|
2317
|
+
*
|
|
2318
|
+
* @example
|
|
2319
|
+
* ```typescript
|
|
2320
|
+
* import { revokeWorkloadToken } from '@enterprisestandard/react/server';
|
|
2321
|
+
*
|
|
2322
|
+
* // Revoke token when workload is decommissioned
|
|
2323
|
+
* await revokeWorkloadToken(accessToken);
|
|
2324
|
+
* ```
|
|
2325
|
+
*/
|
|
2326
|
+
declare function revokeWorkloadToken(token: string, es?: EnterpriseStandard): Promise<void>;
|
|
2327
|
+
/**
|
|
2328
|
+
* Framework-agnostic handler for workload authentication routes.
|
|
2329
|
+
*
|
|
2330
|
+
* The handler reads configuration (handler URLs, validation) directly from the
|
|
2331
|
+
* EnterpriseStandard instance, so no config parameter is needed.
|
|
2332
|
+
*
|
|
2333
|
+
* @param request - Incoming request
|
|
2334
|
+
* @param config - Optional ESConfig to specify which EnterpriseStandard instance to use
|
|
2335
|
+
* @returns Response
|
|
2336
|
+
*
|
|
2337
|
+
* @example
|
|
2338
|
+
* ```typescript
|
|
2339
|
+
* import { workloadHandler } from '@enterprisestandard/react/server';
|
|
2340
|
+
*
|
|
2341
|
+
* // TanStack Start example
|
|
2342
|
+
* export const Route = createFileRoute('/api/workload/$')({
|
|
2343
|
+
* server: {
|
|
2344
|
+
* handlers: ({ createHandlers }) =>
|
|
2345
|
+
* createHandlers({
|
|
2346
|
+
* GET: {
|
|
2347
|
+
* handler: async ({ request }) => {
|
|
2348
|
+
* return workloadHandler(request);
|
|
2349
|
+
* },
|
|
2350
|
+
* },
|
|
2351
|
+
* POST: {
|
|
2352
|
+
* handler: async ({ request }) => {
|
|
2353
|
+
* return workloadHandler(request);
|
|
2354
|
+
* },
|
|
2355
|
+
* },
|
|
2356
|
+
* }),
|
|
2357
|
+
* },
|
|
2358
|
+
* });
|
|
2359
|
+
* ```
|
|
2360
|
+
*/
|
|
2361
|
+
declare function workloadHandler(request: Request, es?: EnterpriseStandard): Promise<Response>;
|
|
2362
|
+
|
|
2363
|
+
/**
|
|
2364
|
+
* Helper gets the user from the Request using the supplied EnterpriseStandard or the default instance
|
|
2365
|
+
*/
|
|
2366
|
+
declare function getUser(request: Request, es?: EnterpriseStandard): Promise<User | undefined>;
|
|
2367
|
+
declare function getRequiredUser(request: Request, es?: EnterpriseStandard): Promise<User>;
|
|
2368
|
+
declare function initiateLogin(config: LoginConfig, es?: EnterpriseStandard): Promise<Response>;
|
|
2369
|
+
declare function callback(request: Request, es?: EnterpriseStandard): Promise<Response>;
|
|
2370
|
+
declare function handler(request: Request, es?: EnterpriseStandard): Promise<Response>;
|
|
2371
|
+
|
|
2372
|
+
/**
|
|
2373
|
+
* Enterprise user with SCIM attributes.
|
|
2374
|
+
* Extends BaseUser (simple fields) with optional complex SCIM fields.
|
|
2375
|
+
* For IAM/provisioning and enterprise directory integration.
|
|
2376
|
+
*/
|
|
2377
|
+
interface EnterpriseUser extends BaseUser {
|
|
2378
|
+
/**
|
|
2379
|
+
* External identifier from the provisioning system
|
|
2380
|
+
*/
|
|
2381
|
+
externalId?: string;
|
|
2382
|
+
/**
|
|
2383
|
+
* Resource metadata
|
|
2384
|
+
*/
|
|
2385
|
+
meta?: {
|
|
2386
|
+
resourceType?: string;
|
|
2387
|
+
created?: string;
|
|
2388
|
+
lastModified?: string;
|
|
2389
|
+
version?: string;
|
|
2390
|
+
location?: string;
|
|
2391
|
+
};
|
|
2392
|
+
/**
|
|
2393
|
+
* SCIM schemas supported by this user
|
|
2394
|
+
*/
|
|
2395
|
+
schemas?: string[];
|
|
2396
|
+
/**
|
|
2397
|
+
* Structured name with family/given names, prefixes, suffixes.
|
|
2398
|
+
* Use alongside the simple `name` string from BaseUser.
|
|
2399
|
+
*/
|
|
2400
|
+
fullName?: Name;
|
|
2401
|
+
/**
|
|
2402
|
+
* Multiple email addresses with types (work, home, etc.).
|
|
2403
|
+
* Use alongside the simple `email` string from BaseUser.
|
|
2404
|
+
*/
|
|
2405
|
+
emails?: Email[];
|
|
2406
|
+
/**
|
|
2407
|
+
* Name for display purposes
|
|
2408
|
+
*/
|
|
2409
|
+
displayName?: string;
|
|
2410
|
+
/**
|
|
2411
|
+
* Casual name to address the user
|
|
2412
|
+
*/
|
|
2413
|
+
nickName?: string;
|
|
2414
|
+
/**
|
|
2415
|
+
* URL to user's online profile
|
|
2416
|
+
*/
|
|
2417
|
+
profileUrl?: string;
|
|
2418
|
+
/**
|
|
2419
|
+
* Job title
|
|
2420
|
+
*/
|
|
2421
|
+
title?: string;
|
|
2422
|
+
/**
|
|
2423
|
+
* User type (e.g., "Employee", "Contractor")
|
|
2424
|
+
*/
|
|
2425
|
+
userType?: string;
|
|
2426
|
+
/**
|
|
2427
|
+
* Preferred language (e.g., "en-US")
|
|
2428
|
+
*/
|
|
2429
|
+
preferredLanguage?: string;
|
|
2430
|
+
/**
|
|
2431
|
+
* Locale for localization (e.g., "en-US")
|
|
2432
|
+
*/
|
|
2433
|
+
locale?: string;
|
|
2434
|
+
/**
|
|
2435
|
+
* Timezone (e.g., "America/New_York")
|
|
2436
|
+
*/
|
|
2437
|
+
timezone?: string;
|
|
2438
|
+
/**
|
|
2439
|
+
* Whether the user account is active
|
|
2440
|
+
*/
|
|
2441
|
+
active?: boolean;
|
|
2442
|
+
/**
|
|
2443
|
+
* Password (for provisioning only, should not be returned)
|
|
2444
|
+
*/
|
|
2445
|
+
password?: string;
|
|
2446
|
+
/**
|
|
2447
|
+
* Phone numbers
|
|
2448
|
+
*/
|
|
2449
|
+
phoneNumbers?: PhoneNumber[];
|
|
2450
|
+
/**
|
|
2451
|
+
* Instant messaging addresses
|
|
2452
|
+
*/
|
|
2453
|
+
ims?: Array<{
|
|
2454
|
+
value: string;
|
|
2455
|
+
display?: string;
|
|
2456
|
+
type?: string;
|
|
2457
|
+
primary?: boolean;
|
|
2458
|
+
}>;
|
|
2459
|
+
/**
|
|
2460
|
+
* Photo URLs
|
|
2461
|
+
*/
|
|
2462
|
+
photos?: Array<{
|
|
2463
|
+
value: string;
|
|
2464
|
+
display?: string;
|
|
2465
|
+
type?: string;
|
|
2466
|
+
primary?: boolean;
|
|
2467
|
+
}>;
|
|
2468
|
+
/**
|
|
2469
|
+
* Physical mailing addresses
|
|
2470
|
+
*/
|
|
2471
|
+
addresses?: Address[];
|
|
2472
|
+
/**
|
|
2473
|
+
* Groups the user belongs to
|
|
2474
|
+
*/
|
|
2475
|
+
groups?: Group[];
|
|
2476
|
+
/**
|
|
2477
|
+
* Entitlements
|
|
2478
|
+
*/
|
|
2479
|
+
entitlements?: Array<{
|
|
2480
|
+
value: string;
|
|
2481
|
+
display?: string;
|
|
2482
|
+
type?: string;
|
|
2483
|
+
primary?: boolean;
|
|
2484
|
+
}>;
|
|
2485
|
+
/**
|
|
2486
|
+
* Roles assigned to the user
|
|
2487
|
+
*/
|
|
2488
|
+
roles?: Role[];
|
|
2489
|
+
/**
|
|
2490
|
+
* X.509 certificates
|
|
2491
|
+
*/
|
|
2492
|
+
x509Certificates?: Array<{
|
|
2493
|
+
value: string;
|
|
2494
|
+
display?: string;
|
|
2495
|
+
type?: string;
|
|
2496
|
+
primary?: boolean;
|
|
2497
|
+
}>;
|
|
2498
|
+
/**
|
|
2499
|
+
* Employee number
|
|
2500
|
+
*/
|
|
2501
|
+
employeeNumber?: string;
|
|
2502
|
+
/**
|
|
2503
|
+
* Cost center
|
|
2504
|
+
*/
|
|
2505
|
+
costCenter?: string;
|
|
2506
|
+
/**
|
|
2507
|
+
* Organization name
|
|
2508
|
+
*/
|
|
2509
|
+
organization?: string;
|
|
2510
|
+
/**
|
|
2511
|
+
* Division name
|
|
2512
|
+
*/
|
|
2513
|
+
division?: string;
|
|
2514
|
+
/**
|
|
2515
|
+
* Department name
|
|
2516
|
+
*/
|
|
2517
|
+
department?: string;
|
|
2518
|
+
/**
|
|
2519
|
+
* User's manager
|
|
2520
|
+
*/
|
|
2521
|
+
manager?: {
|
|
2522
|
+
value: string;
|
|
2523
|
+
$ref?: string;
|
|
2524
|
+
displayName?: string;
|
|
2525
|
+
};
|
|
2526
|
+
}
|
|
2527
|
+
|
|
2528
|
+
declare function SignInLoading({ complete, children }: {
|
|
2529
|
+
complete?: boolean;
|
|
2530
|
+
} & PropsWithChildren): react_jsx_runtime.JSX.Element | null;
|
|
2531
|
+
|
|
2532
|
+
declare function SignedIn({ children }: PropsWithChildren): react_jsx_runtime.JSX.Element | null;
|
|
2533
|
+
|
|
2534
|
+
declare function SignedOut({ children }: PropsWithChildren): react_jsx_runtime.JSX.Element | null;
|
|
2535
|
+
|
|
2536
|
+
type StorageType = 'local' | 'session' | 'memory';
|
|
2537
|
+
interface SSOProviderProps {
|
|
2538
|
+
tenantId?: string;
|
|
2539
|
+
storage?: StorageType;
|
|
2540
|
+
storageKey?: string;
|
|
2541
|
+
userUrl?: string;
|
|
2542
|
+
tokenUrl?: string;
|
|
2543
|
+
refreshUrl?: string;
|
|
2544
|
+
disableListener?: boolean;
|
|
2545
|
+
children: ReactNode;
|
|
2546
|
+
}
|
|
2547
|
+
interface SSOContext {
|
|
2548
|
+
user: User | null;
|
|
2549
|
+
setUser: (user: User | null) => void;
|
|
2550
|
+
isLoading: boolean;
|
|
2551
|
+
tokenUrl?: string;
|
|
2552
|
+
refreshUrl?: string;
|
|
2553
|
+
}
|
|
2554
|
+
declare function SSOProvider({ tenantId, storage, storageKey, userUrl, tokenUrl, refreshUrl, disableListener, children, }: SSOProviderProps): react_jsx_runtime.JSX.Element;
|
|
2555
|
+
declare function useUser(): SSOContext;
|
|
2556
|
+
interface UseTokenReturn {
|
|
2557
|
+
token: string | null;
|
|
2558
|
+
isLoading: boolean;
|
|
2559
|
+
error: Error | null;
|
|
2560
|
+
refresh: () => Promise<void>;
|
|
2561
|
+
}
|
|
2562
|
+
declare function useToken(): UseTokenReturn;
|
|
2563
|
+
declare function logout(logoutUrl: string): Promise<{
|
|
2564
|
+
success: boolean;
|
|
2565
|
+
error?: string;
|
|
2566
|
+
}>;
|
|
2567
|
+
|
|
2568
|
+
declare function getDefaultInstance(): EnterpriseStandard | undefined;
|
|
2569
|
+
|
|
2570
|
+
type EnterpriseStandard = ESConfig & {
|
|
6
2571
|
defaultInstance: boolean;
|
|
7
2572
|
vault: Vault;
|
|
8
2573
|
sso: SSO;
|
|
@@ -19,39 +2584,6 @@ type ESConfig = {
|
|
|
19
2584
|
workload?: WorkloadConfig['validation'];
|
|
20
2585
|
} | SSOHandlerConfig['validation'] | WorkloadConfig['validation'];
|
|
21
2586
|
};
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
export { InMemoryGroupStore
|
|
25
|
-
export type { CreateGroupOptions, CreateUserOptions, GroupsInboundHandlerConfig, IAM, IAMConfig, IAMGroupsInbound, IAMGroupsOutbound, IAMHandlerConfig, IAMUsersInbound, ScimError, ScimListResponse, ScimResult, UsersInboundHandlerConfig, } from './iam';
|
|
26
|
-
export { iam } from './iam';
|
|
27
|
-
export type { SessionStore } from './session-store';
|
|
28
|
-
export { InMemorySessionStore } from './session-store';
|
|
29
|
-
export type { SSO, SSOConfig, SSOHandlerConfig } from './sso';
|
|
30
|
-
export { sso } from './sso';
|
|
31
|
-
export * from './sso-server';
|
|
32
|
-
export type { CreateTenantRequest, CreateTenantResponse, EnvironmentType, StoredTenant, TenantStatus, TenantStore, TenantWebhookPayload, } from './tenant';
|
|
33
|
-
export { InMemoryTenantStore, parseTenantRequest, sendTenantWebhook, serializeESConfig, TenantRequestError, } from './tenant';
|
|
34
|
-
export type { BaseUser } from './types/base-user';
|
|
35
|
-
export type { EnterpriseUser } from './types/enterprise-user';
|
|
36
|
-
export type { IdTokenClaims, OidcCallbackParams, TokenResponse } from './types/oidc-schema';
|
|
37
|
-
export { idTokenClaimsSchema, oidcCallbackSchema, tokenResponseSchema } from './types/oidc-schema';
|
|
38
|
-
export type { Address, Email, EnterpriseExtension, Group, GroupMember, GroupResource, Name, PhoneNumber, Role, User as ScimUser, X509Certificate, } from './types/scim-schema';
|
|
39
|
-
export { groupResourceSchema, userSchema } from './types/scim-schema';
|
|
40
|
-
export type { StandardSchemaV1 } from './types/standard-schema';
|
|
41
|
-
export type { User } from './types/user';
|
|
42
|
-
export type { JWTAssertionClaims, TokenValidationResult, WorkloadTokenResponse, } from './types/workload-schema';
|
|
43
|
-
export { jwtAssertionClaimsSchema, workloadTokenResponseSchema } from './types/workload-schema';
|
|
44
|
-
export { SignInLoading } from './ui/sign-in-loading';
|
|
45
|
-
export { SignedIn } from './ui/signed-in';
|
|
46
|
-
export { SignedOut } from './ui/signed-out';
|
|
47
|
-
export * from './ui/sso-provider';
|
|
48
|
-
export type { StoredUser, UserStore } from './user-store';
|
|
49
|
-
export { InMemoryUserStore } from './user-store';
|
|
50
|
-
export { getDefaultInstance } from './utils';
|
|
51
|
-
export type { Vault } from './vault';
|
|
52
|
-
export { vault } from './vault';
|
|
53
|
-
export type { ClientCredentialsWorkloadConfig, JwtBearerWorkloadConfig, ServerOnlyWorkloadConfig, Workload, WorkloadConfig, WorkloadIdentity, } from './workload';
|
|
54
|
-
export { workload } from './workload';
|
|
55
|
-
export type { CachedWorkloadToken, WorkloadTokenStore } from './workload-token-store';
|
|
56
|
-
export { InMemoryWorkloadTokenStore } from './workload-token-store';
|
|
57
|
-
//# sourceMappingURL=index.d.ts.map
|
|
2587
|
+
declare function enterpriseStandard(appId?: string, initConfig?: ESConfig): Promise<EnterpriseStandard>;
|
|
2588
|
+
|
|
2589
|
+
export { type Address, type BaseUser, type CachedWorkloadToken, type ClientCredentialsWorkloadConfig, type CreateGroupOptions, type CreateTenantRequest, type CreateTenantResponse, type CreateUserOptions, type Email, type EnterpriseExtension, type EnterpriseStandard, type EnterpriseUser, type EnvironmentType, type Group, type GroupMember, type GroupResource, type GroupStore, type GroupsInboundHandlerConfig, type IAM, type IAMConfig, type IAMGroupsInbound, type IAMGroupsOutbound, type IAMHandlerConfig, type IAMUsersInbound, type IdTokenClaims, InMemoryGroupStore, InMemorySessionStore, InMemoryTenantStore, InMemoryUserStore, InMemoryWorkloadTokenStore, type JWTAssertionClaims, type JwtBearerWorkloadConfig, type Name, type OidcCallbackParams, type PhoneNumber, type Role, type SSO, type SSOConfig, type SSOHandlerConfig, SSOProvider, type ScimError, type ScimListResponse, type ScimResult, type User$1 as ScimUser, type ServerOnlyWorkloadConfig, type SessionStore, SignInLoading, SignedIn, SignedOut, StandardSchemaV1, type StoredGroup, type StoredTenant, type StoredUser, TenantRequestError, type TenantStatus, type TenantStore, type TenantWebhookPayload, type TokenResponse, type TokenValidationResult, type User, type UserStore, type UsersInboundHandlerConfig, type Vault, type Workload, type WorkloadConfig, type WorkloadIdentity, type WorkloadTokenResponse, type WorkloadTokenStore, type X509Certificate, callback, enterpriseStandard, getDefaultInstance, getRequiredUser, getUser, getWorkload, getWorkloadToken, groupResourceSchema, handler, iam, idTokenClaimsSchema, initiateLogin, jwtAssertionClaimsSchema, logout, oidcCallbackSchema, parseTenantRequest, revokeWorkloadToken, sendTenantWebhook, serializeESConfig, sso, tokenResponseSchema, useToken, useUser, userSchema, validateWorkloadToken, vault, workload, workloadHandler, workloadTokenResponseSchema };
|