@enterprisestandard/core 0.0.7-beta.20260124.2 → 0.0.7
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 +1375 -1131
- package/dist/index.js +2 -2
- package/package.json +3 -3
package/dist/index.d.ts
CHANGED
|
@@ -1,524 +1,832 @@
|
|
|
1
|
-
import { StandardSchemaV1 as StandardSchemaV15 } from "@standard-schema/spec";
|
|
2
|
-
import { StandardSchemaV1 } from "@standard-schema/spec";
|
|
3
|
-
/**
|
|
4
|
-
* SCIM 2.0 User Resource
|
|
5
|
-
* @see https://datatracker.ietf.org/doc/html/rfc7643#section-4.1
|
|
6
|
-
*/
|
|
7
1
|
/**
|
|
8
|
-
*
|
|
2
|
+
* Base user with simple, developer-friendly attributes.
|
|
3
|
+
* Extended by User (SSO) and EnterpriseUser (SCIM).
|
|
9
4
|
*/
|
|
10
|
-
interface
|
|
11
|
-
/**
|
|
12
|
-
* The full name, including all middle names, titles, and suffixes as appropriate
|
|
13
|
-
*/
|
|
14
|
-
formatted?: string;
|
|
5
|
+
interface BaseUser {
|
|
15
6
|
/**
|
|
16
|
-
*
|
|
7
|
+
* Unique identifier for the user
|
|
17
8
|
*/
|
|
18
|
-
|
|
9
|
+
id?: string;
|
|
19
10
|
/**
|
|
20
|
-
*
|
|
11
|
+
* REQUIRED. Unique identifier for login
|
|
21
12
|
*/
|
|
22
|
-
|
|
13
|
+
userName: string;
|
|
23
14
|
/**
|
|
24
|
-
*
|
|
15
|
+
* REQUIRED. Simple display name
|
|
25
16
|
*/
|
|
26
|
-
|
|
17
|
+
name: string;
|
|
27
18
|
/**
|
|
28
|
-
*
|
|
19
|
+
* REQUIRED. Primary email address
|
|
29
20
|
*/
|
|
30
|
-
|
|
21
|
+
email: string;
|
|
31
22
|
/**
|
|
32
|
-
*
|
|
23
|
+
* URL to user's avatar/profile picture
|
|
33
24
|
*/
|
|
34
|
-
|
|
25
|
+
avatarUrl?: string;
|
|
35
26
|
}
|
|
36
27
|
/**
|
|
37
|
-
*
|
|
28
|
+
* Magic link data stored in the store.
|
|
29
|
+
*
|
|
30
|
+
* @template TExtended - Type-safe custom data that consumers can add to magic links
|
|
38
31
|
*/
|
|
39
|
-
|
|
32
|
+
type MagicLink<TExtended = {}> = {
|
|
40
33
|
/**
|
|
41
|
-
* The
|
|
34
|
+
* The magic link token (unique identifier)
|
|
42
35
|
*/
|
|
43
|
-
|
|
36
|
+
token: string;
|
|
44
37
|
/**
|
|
45
|
-
*
|
|
38
|
+
* User information associated with this magic link
|
|
46
39
|
*/
|
|
47
|
-
|
|
40
|
+
user: BaseUser;
|
|
48
41
|
/**
|
|
49
|
-
*
|
|
42
|
+
* Timestamp when the magic link was created
|
|
50
43
|
*/
|
|
51
|
-
|
|
44
|
+
createdAt: Date;
|
|
52
45
|
/**
|
|
53
|
-
*
|
|
46
|
+
* Timestamp when the magic link expires
|
|
54
47
|
*/
|
|
55
|
-
|
|
56
|
-
}
|
|
57
|
-
/**
|
|
58
|
-
* SCIM Phone Number sub-attribute
|
|
59
|
-
*/
|
|
60
|
-
interface PhoneNumber {
|
|
48
|
+
expiresAt: Date;
|
|
61
49
|
/**
|
|
62
|
-
*
|
|
50
|
+
* Allow consumers to add runtime data to magic links
|
|
63
51
|
*/
|
|
64
|
-
|
|
52
|
+
[key: string]: unknown;
|
|
53
|
+
} & TExtended;
|
|
54
|
+
/**
|
|
55
|
+
* Abstract interface for magic link storage backends.
|
|
56
|
+
*
|
|
57
|
+
* Consumers can implement this interface to use different storage backends:
|
|
58
|
+
* - In-memory (for development/testing)
|
|
59
|
+
* - Redis (for production with fast lookups and automatic expiration)
|
|
60
|
+
* - Database (PostgreSQL, MySQL, etc.)
|
|
61
|
+
*
|
|
62
|
+
* @template TExtended - Type-safe custom data that consumers can add to magic links
|
|
63
|
+
*
|
|
64
|
+
* @example
|
|
65
|
+
* ```typescript
|
|
66
|
+
* // Custom magic link data
|
|
67
|
+
* type MyMagicLinkData = {
|
|
68
|
+
* source: string;
|
|
69
|
+
* metadata: Record<string, unknown>;
|
|
70
|
+
* };
|
|
71
|
+
*
|
|
72
|
+
* // Implement custom store
|
|
73
|
+
* class RedisMagicLinkStore implements MagicLinkStore<MyMagicLinkData> {
|
|
74
|
+
* async create(token: string, user: BaseUser, expiresAt: Date): Promise<void> {
|
|
75
|
+
* const magicLink: MagicLink<MyMagicLinkData> = {
|
|
76
|
+
* token,
|
|
77
|
+
* user,
|
|
78
|
+
* createdAt: new Date(),
|
|
79
|
+
* expiresAt,
|
|
80
|
+
* source: 'api',
|
|
81
|
+
* metadata: {},
|
|
82
|
+
* };
|
|
83
|
+
* const ttl = Math.floor((expiresAt.getTime() - Date.now()) / 1000);
|
|
84
|
+
* await redis.setex(`magic-link:${token}`, ttl, JSON.stringify(magicLink));
|
|
85
|
+
* }
|
|
86
|
+
* // ... other methods
|
|
87
|
+
* }
|
|
88
|
+
* ```
|
|
89
|
+
*/
|
|
90
|
+
interface MagicLinkStore<TExtended = {}> {
|
|
65
91
|
/**
|
|
66
|
-
*
|
|
92
|
+
* Create a new magic link in the store.
|
|
93
|
+
*
|
|
94
|
+
* @param token - The magic link token (unique identifier)
|
|
95
|
+
* @param user - The user information to associate with this magic link
|
|
96
|
+
* @param expiresAt - When the magic link expires
|
|
97
|
+
* @throws Error if magic link with same token already exists
|
|
67
98
|
*/
|
|
68
|
-
|
|
99
|
+
create(token: string, user: BaseUser, expiresAt: Date): Promise<void>;
|
|
69
100
|
/**
|
|
70
|
-
*
|
|
101
|
+
* Retrieve a magic link by its token.
|
|
102
|
+
*
|
|
103
|
+
* @param token - The magic link token
|
|
104
|
+
* @returns The magic link if found and not expired, null otherwise
|
|
71
105
|
*/
|
|
72
|
-
|
|
106
|
+
get(token: string): Promise<MagicLink<TExtended> | null>;
|
|
73
107
|
/**
|
|
74
|
-
*
|
|
108
|
+
* Delete a magic link by its token.
|
|
109
|
+
*
|
|
110
|
+
* Used after a magic link has been consumed (one-time use).
|
|
111
|
+
*
|
|
112
|
+
* @param token - The magic link token to delete
|
|
75
113
|
*/
|
|
76
|
-
|
|
114
|
+
delete(token: string): Promise<void>;
|
|
77
115
|
}
|
|
78
116
|
/**
|
|
79
|
-
*
|
|
117
|
+
* In-memory magic link store implementation using Maps.
|
|
118
|
+
*
|
|
119
|
+
* Suitable for:
|
|
120
|
+
* - Development and testing
|
|
121
|
+
* - Single-server deployments
|
|
122
|
+
* - Applications without high availability requirements
|
|
123
|
+
*
|
|
124
|
+
* NOT suitable for:
|
|
125
|
+
* - Multi-server deployments (magic links not shared)
|
|
126
|
+
* - High availability scenarios (magic links lost on restart)
|
|
127
|
+
* - Production applications with distributed architecture
|
|
128
|
+
*
|
|
129
|
+
* For production, implement MagicLinkStore with Redis or a database.
|
|
130
|
+
*
|
|
131
|
+
* @template TExtended - Type-safe custom data that consumers can add to magic links
|
|
80
132
|
*/
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
133
|
+
declare class InMemoryMagicLinkStore<TExtended = {}> implements MagicLinkStore<TExtended> {
|
|
134
|
+
private magicLinks;
|
|
135
|
+
create(token: string, user: BaseUser, expiresAt: Date): Promise<void>;
|
|
136
|
+
get(token: string): Promise<MagicLink<TExtended> | null>;
|
|
137
|
+
delete(token: string): Promise<void>;
|
|
138
|
+
}
|
|
139
|
+
/**
|
|
140
|
+
* Session management for tracking user sessions and enabling backchannel logout.
|
|
141
|
+
*
|
|
142
|
+
* Session stores are optional - the package works with JWT cookies alone.
|
|
143
|
+
* Sessions are only required for backchannel logout functionality.
|
|
144
|
+
*
|
|
145
|
+
* ## Session Validation Strategies
|
|
146
|
+
*
|
|
147
|
+
* When using a session store, you can configure when sessions are validated:
|
|
148
|
+
*
|
|
149
|
+
* ### 'always' (default)
|
|
150
|
+
* Validates session on every authenticated request.
|
|
151
|
+
* - **Security**: Maximum - immediate session revocation
|
|
152
|
+
* - **Performance**: InMemory ~0.00005ms, Redis ~1-2ms per request
|
|
153
|
+
* - **Backchannel Logout**: Takes effect immediately
|
|
154
|
+
* - **Use when**: Security is paramount, using InMemory or Redis backend
|
|
155
|
+
*
|
|
156
|
+
* ### 'refresh-only'
|
|
157
|
+
* Validates session only during token refresh (typically every 5-15 minutes).
|
|
158
|
+
* - **Security**: Good - 5-15 minute revocation window
|
|
159
|
+
* - **Performance**: 99% reduction in session lookups
|
|
160
|
+
* - **Backchannel Logout**: Takes effect within token TTL (5-15 min)
|
|
161
|
+
* - **Use when**: Performance is critical AND delayed revocation is acceptable
|
|
162
|
+
* - **WARNING**: Compromised sessions remain valid until next refresh
|
|
163
|
+
*
|
|
164
|
+
* ### 'disabled'
|
|
165
|
+
* Never validates sessions against the store.
|
|
166
|
+
* - **Security**: None - backchannel logout doesn't work
|
|
167
|
+
* - **Performance**: No overhead
|
|
168
|
+
* - **Use when**: Cookie-only mode without session store
|
|
169
|
+
* - **WARNING**: Do not use with sessionStore configured
|
|
170
|
+
*
|
|
171
|
+
* ## Performance Characteristics
|
|
172
|
+
*
|
|
173
|
+
* | Backend | Lookup Time | Impact on Request | Recommendation |
|
|
174
|
+
* |--------------|-------------|-------------------|------------------------|
|
|
175
|
+
* | InMemory | <0.00005ms | Negligible | Use 'always' |
|
|
176
|
+
* | Redis | 1-2ms | 2-4% increase | Use 'always' or test |
|
|
177
|
+
* | Database | 5-20ms | 10-40% increase | Use Redis cache layer |
|
|
178
|
+
*
|
|
179
|
+
* ## Example Usage
|
|
180
|
+
*
|
|
181
|
+
* ```typescript
|
|
182
|
+
* import { sso, InMemorySessionStore } from '@enterprisestandard/react/server';
|
|
183
|
+
*
|
|
184
|
+
* // Maximum security (default)
|
|
185
|
+
* const secure = sso({
|
|
186
|
+
* // ... other config
|
|
187
|
+
* sessionStore: new InMemorySessionStore(),
|
|
188
|
+
* session_validation: 'always', // Immediate revocation
|
|
189
|
+
* });
|
|
190
|
+
*
|
|
191
|
+
* // High performance
|
|
192
|
+
* const fast = sso({
|
|
193
|
+
* // ... other config
|
|
194
|
+
* sessionStore: new InMemorySessionStore(),
|
|
195
|
+
* session_validation: {
|
|
196
|
+
* strategy: 'refresh-only' // 5-15 min revocation delay
|
|
197
|
+
* }
|
|
198
|
+
* });
|
|
199
|
+
* ```
|
|
200
|
+
*/
|
|
201
|
+
/**
|
|
202
|
+
* Core session data tracked for each authenticated user session.
|
|
203
|
+
*
|
|
204
|
+
* @template TExtended - Type-safe custom data that consumers can add to sessions
|
|
205
|
+
*/
|
|
206
|
+
type Session<TExtended = {}> = {
|
|
94
207
|
/**
|
|
95
|
-
*
|
|
208
|
+
* Session ID from the Identity Provider (from `sid` claim in ID token).
|
|
209
|
+
* This is the unique identifier for the session.
|
|
96
210
|
*/
|
|
97
|
-
|
|
211
|
+
sid: string;
|
|
98
212
|
/**
|
|
99
|
-
*
|
|
213
|
+
* Subject identifier (user ID) from the Identity Provider.
|
|
214
|
+
* From the `sub` claim in the ID token.
|
|
100
215
|
*/
|
|
101
|
-
|
|
216
|
+
sub: string;
|
|
102
217
|
/**
|
|
103
|
-
*
|
|
218
|
+
* Timestamp when the session was created.
|
|
104
219
|
*/
|
|
105
|
-
|
|
220
|
+
createdAt: Date;
|
|
106
221
|
/**
|
|
107
|
-
*
|
|
222
|
+
* Timestamp of the last activity in this session.
|
|
223
|
+
* Can be updated to track session activity.
|
|
108
224
|
*/
|
|
109
|
-
|
|
225
|
+
lastActivityAt: Date;
|
|
110
226
|
/**
|
|
111
|
-
*
|
|
227
|
+
* Allow consumers to add runtime data to sessions.
|
|
112
228
|
*/
|
|
113
|
-
|
|
114
|
-
}
|
|
229
|
+
[key: string]: unknown;
|
|
230
|
+
} & TExtended;
|
|
115
231
|
/**
|
|
116
|
-
*
|
|
232
|
+
* Abstract interface for session storage backends.
|
|
233
|
+
*
|
|
234
|
+
* Consumers can implement this interface to use different storage backends:
|
|
235
|
+
* - Redis
|
|
236
|
+
* - Database (PostgreSQL, MySQL, etc.)
|
|
237
|
+
* - Distributed cache
|
|
238
|
+
* - Custom solutions
|
|
239
|
+
*
|
|
240
|
+
* @template TExtended - Type-safe custom data that consumers can add to sessions
|
|
241
|
+
*
|
|
242
|
+
* @example
|
|
243
|
+
* ```typescript
|
|
244
|
+
* // Custom session data
|
|
245
|
+
* type MySessionData = {
|
|
246
|
+
* ipAddress: string;
|
|
247
|
+
* userAgent: string;
|
|
248
|
+
* };
|
|
249
|
+
*
|
|
250
|
+
* // Implement custom store
|
|
251
|
+
* class RedisSessionStore implements SessionStore<MySessionData> {
|
|
252
|
+
* async create(session: Session<MySessionData>): Promise<void> {
|
|
253
|
+
* await redis.set(`session:${session.sid}`, JSON.stringify(session));
|
|
254
|
+
* }
|
|
255
|
+
* // ... other methods
|
|
256
|
+
* }
|
|
257
|
+
* ```
|
|
117
258
|
*/
|
|
118
|
-
interface
|
|
259
|
+
interface SessionStore<TExtended = {}> {
|
|
119
260
|
/**
|
|
120
|
-
*
|
|
261
|
+
* Create a new session in the store.
|
|
262
|
+
*
|
|
263
|
+
* @param session - The session data to store
|
|
264
|
+
* @throws Error if session with same sid already exists
|
|
121
265
|
*/
|
|
122
|
-
|
|
266
|
+
create(session: Session<TExtended>): Promise<void>;
|
|
123
267
|
/**
|
|
124
|
-
*
|
|
268
|
+
* Retrieve a session by its IdP session ID (sid).
|
|
269
|
+
*
|
|
270
|
+
* @param sid - The session.sid from the Identity Provider
|
|
271
|
+
* @returns The session if found, null otherwise
|
|
125
272
|
*/
|
|
126
|
-
|
|
273
|
+
get(sid: string): Promise<Session<TExtended> | null>;
|
|
127
274
|
/**
|
|
128
|
-
*
|
|
275
|
+
* Update an existing session with partial data.
|
|
276
|
+
*
|
|
277
|
+
* Commonly used to update lastActivityAt or add custom fields.
|
|
278
|
+
*
|
|
279
|
+
* @param sid - The session.sid to update
|
|
280
|
+
* @param data - Partial session data to merge
|
|
281
|
+
* @throws Error if session not found
|
|
129
282
|
*/
|
|
130
|
-
|
|
283
|
+
update(sid: string, data: Partial<Session<TExtended>>): Promise<void>;
|
|
131
284
|
/**
|
|
132
|
-
*
|
|
133
|
-
|
|
134
|
-
|
|
285
|
+
* Delete a session by its IdP session ID (sid).
|
|
286
|
+
*
|
|
287
|
+
* Used for both normal logout and backchannel logout flows.
|
|
288
|
+
*
|
|
289
|
+
* @param sid - The session.sid to delete
|
|
290
|
+
*/
|
|
291
|
+
delete(sid: string): Promise<void>;
|
|
135
292
|
}
|
|
136
293
|
/**
|
|
137
|
-
*
|
|
294
|
+
* In-memory session store implementation using Maps.
|
|
295
|
+
*
|
|
296
|
+
* Suitable for:
|
|
297
|
+
* - Development and testing
|
|
298
|
+
* - Single-server deployments
|
|
299
|
+
* - Applications without high availability requirements
|
|
300
|
+
*
|
|
301
|
+
* NOT suitable for:
|
|
302
|
+
* - Multi-server deployments (sessions not shared)
|
|
303
|
+
* - High availability scenarios (sessions lost on restart)
|
|
304
|
+
* - Production applications with distributed architecture
|
|
305
|
+
*
|
|
306
|
+
* For production, implement SessionStore with Redis or a database.
|
|
307
|
+
*
|
|
308
|
+
* @template TExtended - Type-safe custom data that consumers can add to sessions
|
|
138
309
|
*/
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
* The URI of the corresponding member resource
|
|
146
|
-
*/
|
|
147
|
-
$ref?: string;
|
|
148
|
-
/**
|
|
149
|
-
* A human-readable name of the member
|
|
150
|
-
*/
|
|
151
|
-
display?: string;
|
|
152
|
-
/**
|
|
153
|
-
* The type of the member (e.g., "User" or "Group")
|
|
154
|
-
*/
|
|
155
|
-
type?: "User" | "Group";
|
|
310
|
+
declare class InMemorySessionStore<TExtended = {}> implements SessionStore<TExtended> {
|
|
311
|
+
private sessions;
|
|
312
|
+
create(session: Session<TExtended>): Promise<void>;
|
|
313
|
+
get(sid: string): Promise<Session<TExtended> | null>;
|
|
314
|
+
update(sid: string, data: Partial<Session<TExtended>>): Promise<void>;
|
|
315
|
+
delete(sid: string): Promise<void>;
|
|
156
316
|
}
|
|
317
|
+
import { StandardSchemaV1 } from "@standard-schema/spec";
|
|
157
318
|
/**
|
|
158
|
-
*
|
|
159
|
-
* @see https://
|
|
319
|
+
* OIDC Code Flow Callback URL Parameters
|
|
320
|
+
* @see https://openid.net/specs/openid-connect-core-1_0.html#CodeFlowAuth
|
|
160
321
|
*/
|
|
161
|
-
interface
|
|
322
|
+
interface OidcCallbackParams {
|
|
162
323
|
/**
|
|
163
|
-
* REQUIRED. The
|
|
324
|
+
* REQUIRED. The authorization code returned from the authorization server.
|
|
164
325
|
*/
|
|
165
|
-
|
|
326
|
+
code: string;
|
|
166
327
|
/**
|
|
167
|
-
*
|
|
328
|
+
* REQUIRED if the "state" parameter was present in the client authorization request.
|
|
329
|
+
* The exact value received from the client.
|
|
168
330
|
*/
|
|
169
|
-
|
|
331
|
+
state?: string;
|
|
170
332
|
/**
|
|
171
|
-
*
|
|
333
|
+
* RECOMMENDED. The session state value. Clients should use this to verify the session state.
|
|
172
334
|
*/
|
|
173
|
-
|
|
335
|
+
session_state?: string;
|
|
174
336
|
/**
|
|
175
|
-
*
|
|
337
|
+
* OAuth 2.0 error code if the authorization request failed.
|
|
176
338
|
*/
|
|
177
|
-
|
|
178
|
-
resourceType?: string;
|
|
179
|
-
created?: string;
|
|
180
|
-
lastModified?: string;
|
|
181
|
-
location?: string;
|
|
182
|
-
version?: string;
|
|
183
|
-
};
|
|
339
|
+
error?: string;
|
|
184
340
|
/**
|
|
185
|
-
*
|
|
341
|
+
* Human-readable ASCII text providing additional information for the error.
|
|
186
342
|
*/
|
|
187
|
-
|
|
343
|
+
error_description?: string;
|
|
188
344
|
/**
|
|
189
|
-
* A
|
|
345
|
+
* A URI identifying a human-readable web page with information about the error.
|
|
190
346
|
*/
|
|
191
|
-
|
|
347
|
+
error_uri?: string;
|
|
348
|
+
/**
|
|
349
|
+
* The "iss" (issuer) parameter identifies the principal that issued the response.
|
|
350
|
+
* This is typically used in the implicit flow.
|
|
351
|
+
*/
|
|
352
|
+
iss?: string;
|
|
192
353
|
}
|
|
193
354
|
/**
|
|
194
|
-
*
|
|
355
|
+
* Creates a StandardSchemaV1 for validating OIDC callback URL parameters.
|
|
356
|
+
* @param vendor - The name of the vendor creating this schema
|
|
357
|
+
* @returns A StandardSchemaV1 instance for OIDC callback parameters
|
|
195
358
|
*/
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
* A Boolean value indicating the 'primary' or preferred attribute value
|
|
211
|
-
*/
|
|
212
|
-
primary?: boolean;
|
|
359
|
+
declare function oidcCallbackSchema(vendor: string): StandardSchemaV1<Record<string, unknown>, OidcCallbackParams>;
|
|
360
|
+
/**
|
|
361
|
+
* Token Response from IdP
|
|
362
|
+
*/
|
|
363
|
+
interface TokenResponse {
|
|
364
|
+
access_token: string;
|
|
365
|
+
id_token: string;
|
|
366
|
+
refresh_token?: string;
|
|
367
|
+
token_type: string;
|
|
368
|
+
expires_in?: number;
|
|
369
|
+
scope?: string;
|
|
370
|
+
refresh_expires_in?: number;
|
|
371
|
+
session_state?: string;
|
|
372
|
+
expires?: string;
|
|
213
373
|
}
|
|
214
374
|
/**
|
|
215
|
-
*
|
|
375
|
+
* Creates a StandardSchemaV1 for validating OIDC Token Responses.
|
|
376
|
+
* @param vendor - The name of the vendor creating this schema
|
|
377
|
+
* @returns A StandardSchemaV1 instance for Token Response validation
|
|
216
378
|
*/
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
primary?: boolean;
|
|
379
|
+
declare function tokenResponseSchema(vendor: string): StandardSchemaV1<Record<string, unknown>, TokenResponse>;
|
|
380
|
+
/**
|
|
381
|
+
* ID Token Claims
|
|
382
|
+
*/
|
|
383
|
+
interface IdTokenClaims {
|
|
384
|
+
iss?: string;
|
|
385
|
+
aud?: string;
|
|
386
|
+
exp?: number;
|
|
387
|
+
iat?: number;
|
|
388
|
+
sub?: string;
|
|
389
|
+
sid?: string;
|
|
390
|
+
name?: string;
|
|
391
|
+
email?: string;
|
|
392
|
+
preferred_username?: string;
|
|
393
|
+
picture?: string;
|
|
394
|
+
[key: string]: unknown;
|
|
234
395
|
}
|
|
235
396
|
/**
|
|
236
|
-
*
|
|
237
|
-
* @
|
|
397
|
+
* Creates a StandardSchemaV1 for validating ID Token Claims.
|
|
398
|
+
* @param vendor - The name of the vendor creating this schema
|
|
399
|
+
* @returns A StandardSchemaV1 instance for ID Token Claims validation
|
|
238
400
|
*/
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
* Identifies the name of a cost center
|
|
246
|
-
*/
|
|
247
|
-
costCenter?: string;
|
|
248
|
-
/**
|
|
249
|
-
* Identifies the name of an organization
|
|
250
|
-
*/
|
|
251
|
-
organization?: string;
|
|
252
|
-
/**
|
|
253
|
-
* Identifies the name of a division
|
|
254
|
-
*/
|
|
255
|
-
division?: string;
|
|
256
|
-
/**
|
|
257
|
-
* Identifies the name of a department
|
|
258
|
-
*/
|
|
259
|
-
department?: string;
|
|
401
|
+
declare function idTokenClaimsSchema(vendor: string): StandardSchemaV1<Record<string, unknown>, IdTokenClaims>;
|
|
402
|
+
/**
|
|
403
|
+
* Primary user type for SSO/OIDC applications.
|
|
404
|
+
* Extends BaseUser with SSO-specific data.
|
|
405
|
+
*/
|
|
406
|
+
interface User extends BaseUser {
|
|
260
407
|
/**
|
|
261
|
-
*
|
|
408
|
+
* SSO/OIDC authentication data
|
|
262
409
|
*/
|
|
263
|
-
|
|
410
|
+
sso: {
|
|
264
411
|
/**
|
|
265
|
-
*
|
|
412
|
+
* ID Token claims from the identity provider
|
|
266
413
|
*/
|
|
267
|
-
|
|
414
|
+
profile: IdTokenClaims;
|
|
268
415
|
/**
|
|
269
|
-
*
|
|
416
|
+
* Tenant/organization information
|
|
270
417
|
*/
|
|
271
|
-
|
|
418
|
+
tenant: {
|
|
419
|
+
id: string;
|
|
420
|
+
name: string;
|
|
421
|
+
};
|
|
272
422
|
/**
|
|
273
|
-
*
|
|
423
|
+
* OAuth scopes granted
|
|
274
424
|
*/
|
|
275
|
-
|
|
425
|
+
scope?: string;
|
|
426
|
+
/**
|
|
427
|
+
* Token type (typically "Bearer")
|
|
428
|
+
*/
|
|
429
|
+
tokenType: string;
|
|
430
|
+
/**
|
|
431
|
+
* Session state from the identity provider
|
|
432
|
+
*/
|
|
433
|
+
sessionState?: string;
|
|
434
|
+
/**
|
|
435
|
+
* Token expiration time
|
|
436
|
+
*/
|
|
437
|
+
expires: Date;
|
|
276
438
|
};
|
|
277
439
|
}
|
|
278
440
|
/**
|
|
279
|
-
*
|
|
441
|
+
* Stored user data with required id and tracking metadata.
|
|
442
|
+
*
|
|
443
|
+
* Extends the SSO User type with:
|
|
444
|
+
* - Required `id` (the `sub` claim from the IdP)
|
|
445
|
+
* - Timestamps for tracking when users were first seen and last updated
|
|
446
|
+
* - Optional custom extended data
|
|
447
|
+
*
|
|
448
|
+
* @template TExtended - Type-safe custom data that consumers can add to users
|
|
280
449
|
*/
|
|
281
|
-
|
|
282
|
-
/**
|
|
283
|
-
* REQUIRED. Unique identifier for the User, typically from the provider
|
|
284
|
-
*/
|
|
285
|
-
id?: string;
|
|
286
|
-
/**
|
|
287
|
-
* REQUIRED. A unique identifier for a SCIM resource as defined by the service provider
|
|
288
|
-
*/
|
|
289
|
-
externalId?: string;
|
|
450
|
+
type StoredUser<TExtended = {}> = User & {
|
|
290
451
|
/**
|
|
291
|
-
*
|
|
452
|
+
* Required unique identifier (the `sub` claim from the IdP).
|
|
453
|
+
* This is the primary key for user storage.
|
|
292
454
|
*/
|
|
293
|
-
|
|
294
|
-
resourceType?: string;
|
|
295
|
-
created?: string;
|
|
296
|
-
lastModified?: string;
|
|
297
|
-
location?: string;
|
|
298
|
-
version?: string;
|
|
299
|
-
};
|
|
455
|
+
id: string;
|
|
300
456
|
/**
|
|
301
|
-
*
|
|
457
|
+
* Timestamp when the user was first stored.
|
|
302
458
|
*/
|
|
303
|
-
|
|
459
|
+
createdAt: Date;
|
|
304
460
|
/**
|
|
305
|
-
*
|
|
461
|
+
* Timestamp when the user was last updated (e.g., on re-login).
|
|
306
462
|
*/
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
463
|
+
updatedAt: Date;
|
|
464
|
+
} & TExtended;
|
|
465
|
+
/**
|
|
466
|
+
* Abstract interface for user storage backends.
|
|
467
|
+
*
|
|
468
|
+
* Consumers can implement this interface to use different storage backends:
|
|
469
|
+
* - In-memory (for development/testing)
|
|
470
|
+
* - Redis (for production with fast lookups)
|
|
471
|
+
* - Database (PostgreSQL, MySQL, etc.)
|
|
472
|
+
*
|
|
473
|
+
* @template TExtended - Type-safe custom data that consumers can add to users
|
|
474
|
+
*
|
|
475
|
+
* @example
|
|
476
|
+
* ```typescript
|
|
477
|
+
* // Custom user data
|
|
478
|
+
* type MyUserData = {
|
|
479
|
+
* department: string;
|
|
480
|
+
* roles: string[];
|
|
481
|
+
* };
|
|
482
|
+
*
|
|
483
|
+
* // Implement custom store
|
|
484
|
+
* class RedisUserStore implements UserStore<MyUserData> {
|
|
485
|
+
* async get(sub: string): Promise<StoredUser<MyUserData> | null> {
|
|
486
|
+
* const data = await redis.get(`user:${sub}`);
|
|
487
|
+
* return data ? JSON.parse(data) : null;
|
|
488
|
+
* }
|
|
489
|
+
* // ... other methods
|
|
490
|
+
* }
|
|
491
|
+
* ```
|
|
492
|
+
*/
|
|
493
|
+
interface UserStore<TExtended = {}> {
|
|
316
494
|
/**
|
|
317
|
-
*
|
|
495
|
+
* Retrieve a user by their subject identifier (sub).
|
|
496
|
+
*
|
|
497
|
+
* @param sub - The user's unique identifier from the IdP
|
|
498
|
+
* @returns The user if found, null otherwise
|
|
318
499
|
*/
|
|
319
|
-
|
|
500
|
+
get(sub: string): Promise<StoredUser<TExtended> | null>;
|
|
320
501
|
/**
|
|
321
|
-
*
|
|
502
|
+
* Retrieve a user by their email address.
|
|
503
|
+
*
|
|
504
|
+
* @param email - The user's email address
|
|
505
|
+
* @returns The user if found, null otherwise
|
|
322
506
|
*/
|
|
323
|
-
|
|
507
|
+
getByEmail(email: string): Promise<StoredUser<TExtended> | null>;
|
|
324
508
|
/**
|
|
325
|
-
*
|
|
509
|
+
* Retrieve a user by their username.
|
|
510
|
+
*
|
|
511
|
+
* @param userName - The user's username
|
|
512
|
+
* @returns The user if found, null otherwise
|
|
326
513
|
*/
|
|
327
|
-
|
|
514
|
+
getByUserName(userName: string): Promise<StoredUser<TExtended> | null>;
|
|
328
515
|
/**
|
|
329
|
-
*
|
|
516
|
+
* Create or update a user in the store.
|
|
517
|
+
*
|
|
518
|
+
* If a user with the same `id` (sub) exists, it will be updated.
|
|
519
|
+
* Otherwise, a new user will be created.
|
|
520
|
+
*
|
|
521
|
+
* @param user - The user data to store
|
|
330
522
|
*/
|
|
331
|
-
|
|
523
|
+
upsert(user: StoredUser<TExtended>): Promise<void>;
|
|
332
524
|
/**
|
|
333
|
-
*
|
|
525
|
+
* Delete a user by their subject identifier (sub).
|
|
526
|
+
*
|
|
527
|
+
* @param sub - The user's unique identifier to delete
|
|
334
528
|
*/
|
|
335
|
-
|
|
529
|
+
delete(sub: string): Promise<void>;
|
|
530
|
+
}
|
|
531
|
+
/**
|
|
532
|
+
* In-memory user store implementation using Maps.
|
|
533
|
+
*
|
|
534
|
+
* Suitable for:
|
|
535
|
+
* - Development and testing
|
|
536
|
+
* - Single-server deployments
|
|
537
|
+
* - Applications without high availability requirements
|
|
538
|
+
*
|
|
539
|
+
* NOT suitable for:
|
|
540
|
+
* - Multi-server deployments (users not shared)
|
|
541
|
+
* - High availability scenarios (users lost on restart)
|
|
542
|
+
* - Production applications with distributed architecture
|
|
543
|
+
*
|
|
544
|
+
* For production, implement UserStore with Redis or a database.
|
|
545
|
+
*
|
|
546
|
+
* @template TExtended - Type-safe custom data that consumers can add to users
|
|
547
|
+
*/
|
|
548
|
+
declare class InMemoryUserStore<TExtended = {}> implements UserStore<TExtended> {
|
|
549
|
+
/** Primary storage: sub -> user */
|
|
550
|
+
private users;
|
|
551
|
+
/** Secondary index: email -> sub */
|
|
552
|
+
private emailIndex;
|
|
553
|
+
/** Secondary index: userName -> sub */
|
|
554
|
+
private userNameIndex;
|
|
555
|
+
get(sub: string): Promise<StoredUser<TExtended> | null>;
|
|
556
|
+
getByEmail(email: string): Promise<StoredUser<TExtended> | null>;
|
|
557
|
+
getByUserName(userName: string): Promise<StoredUser<TExtended> | null>;
|
|
558
|
+
upsert(user: StoredUser<TExtended>): Promise<void>;
|
|
559
|
+
delete(sub: string): Promise<void>;
|
|
560
|
+
}
|
|
561
|
+
import { StandardSchemaV1 as StandardSchemaV13 } from "@standard-schema/spec";
|
|
562
|
+
import { StandardSchemaV1 as StandardSchemaV12 } from "@standard-schema/spec";
|
|
563
|
+
/**
|
|
564
|
+
* JWT Assertion Claims for OAuth2 JWT Bearer Grant (RFC 7523) and OAuth2 Access Tokens
|
|
565
|
+
* @see https://datatracker.ietf.org/doc/html/rfc7523
|
|
566
|
+
* @see https://datatracker.ietf.org/doc/html/rfc9068
|
|
567
|
+
*/
|
|
568
|
+
interface JWTAssertionClaims {
|
|
336
569
|
/**
|
|
337
|
-
*
|
|
570
|
+
* REQUIRED. Issuer - the workload identity (e.g., SPIFFE ID) or authorization server
|
|
338
571
|
*/
|
|
339
|
-
|
|
572
|
+
iss: string;
|
|
340
573
|
/**
|
|
341
|
-
*
|
|
574
|
+
* REQUIRED. Subject - the workload identity or service account
|
|
342
575
|
*/
|
|
343
|
-
|
|
576
|
+
sub: string;
|
|
344
577
|
/**
|
|
345
|
-
*
|
|
578
|
+
* OPTIONAL. Audience - may be a string or array of strings
|
|
579
|
+
* Note: Required for JWT assertions, but may be absent in OAuth2 access tokens
|
|
346
580
|
*/
|
|
347
|
-
|
|
581
|
+
aud?: string | string[];
|
|
348
582
|
/**
|
|
349
|
-
*
|
|
583
|
+
* REQUIRED. Expiration time (Unix timestamp)
|
|
350
584
|
*/
|
|
351
|
-
|
|
585
|
+
exp: number;
|
|
352
586
|
/**
|
|
353
|
-
*
|
|
587
|
+
* REQUIRED. Issued at time (Unix timestamp)
|
|
354
588
|
*/
|
|
355
|
-
|
|
589
|
+
iat: number;
|
|
356
590
|
/**
|
|
357
|
-
*
|
|
591
|
+
* OPTIONAL. JWT ID - unique identifier for this token
|
|
592
|
+
* Note: Required for JWT assertions, optional for access tokens
|
|
358
593
|
*/
|
|
359
|
-
|
|
360
|
-
value: string;
|
|
361
|
-
display?: string;
|
|
362
|
-
type?: string;
|
|
363
|
-
primary?: boolean;
|
|
364
|
-
}>;
|
|
594
|
+
jti?: string;
|
|
365
595
|
/**
|
|
366
|
-
*
|
|
596
|
+
* OPTIONAL. Requested OAuth scopes (space-delimited)
|
|
367
597
|
*/
|
|
368
|
-
|
|
369
|
-
value: string;
|
|
370
|
-
display?: string;
|
|
371
|
-
type?: string;
|
|
372
|
-
primary?: boolean;
|
|
373
|
-
}>;
|
|
598
|
+
scope?: string;
|
|
374
599
|
/**
|
|
375
|
-
*
|
|
600
|
+
* Allow additional claims for extensibility
|
|
376
601
|
*/
|
|
377
|
-
|
|
602
|
+
[key: string]: unknown;
|
|
603
|
+
}
|
|
604
|
+
/**
|
|
605
|
+
* Creates a StandardSchemaV1 for validating JWT Assertion Claims.
|
|
606
|
+
* @param vendor - The name of the vendor creating this schema
|
|
607
|
+
* @returns A StandardSchemaV1 instance for JWT Assertion Claims validation
|
|
608
|
+
*/
|
|
609
|
+
declare function jwtAssertionClaimsSchema(vendor: string): StandardSchemaV12<Record<string, unknown>, JWTAssertionClaims>;
|
|
610
|
+
/**
|
|
611
|
+
* Workload Token Response from OAuth2 token endpoint
|
|
612
|
+
* @see https://datatracker.ietf.org/doc/html/rfc6749#section-5.1
|
|
613
|
+
*/
|
|
614
|
+
interface WorkloadTokenResponse {
|
|
378
615
|
/**
|
|
379
|
-
*
|
|
616
|
+
* REQUIRED. The access token issued by the authorization server.
|
|
380
617
|
*/
|
|
381
|
-
|
|
618
|
+
access_token: string;
|
|
382
619
|
/**
|
|
383
|
-
*
|
|
620
|
+
* REQUIRED. The type of the token (typically "Bearer").
|
|
384
621
|
*/
|
|
385
|
-
|
|
386
|
-
value: string;
|
|
387
|
-
display?: string;
|
|
388
|
-
type?: string;
|
|
389
|
-
primary?: boolean;
|
|
390
|
-
}>;
|
|
622
|
+
token_type: string;
|
|
391
623
|
/**
|
|
392
|
-
*
|
|
624
|
+
* RECOMMENDED. The lifetime in seconds of the access token.
|
|
393
625
|
*/
|
|
394
|
-
|
|
626
|
+
expires_in?: number;
|
|
395
627
|
/**
|
|
396
|
-
*
|
|
628
|
+
* OPTIONAL. The scope of the access token.
|
|
397
629
|
*/
|
|
398
|
-
|
|
630
|
+
scope?: string;
|
|
399
631
|
/**
|
|
400
|
-
*
|
|
632
|
+
* OPTIONAL. The refresh token (rarely used for workload identities).
|
|
401
633
|
*/
|
|
402
|
-
|
|
634
|
+
refresh_token?: string;
|
|
403
635
|
/**
|
|
404
|
-
*
|
|
636
|
+
* OPTIONAL. The expiration time as an ISO 8601 string.
|
|
405
637
|
*/
|
|
406
|
-
|
|
638
|
+
expires?: string;
|
|
407
639
|
}
|
|
408
640
|
/**
|
|
409
|
-
* Creates a StandardSchemaV1 for validating
|
|
410
|
-
* @param vendor - The name of the vendor creating this schema
|
|
411
|
-
* @returns A StandardSchemaV1 instance for SCIM User resources
|
|
412
|
-
*/
|
|
413
|
-
declare function userSchema(vendor: string): StandardSchemaV1<Record<string, unknown>, User>;
|
|
414
|
-
/**
|
|
415
|
-
* Creates a StandardSchemaV1 for validating SCIM Group resources.
|
|
641
|
+
* Creates a StandardSchemaV1 for validating Workload Token Responses.
|
|
416
642
|
* @param vendor - The name of the vendor creating this schema
|
|
417
|
-
* @returns A StandardSchemaV1 instance for
|
|
643
|
+
* @returns A StandardSchemaV1 instance for Workload Token Response validation
|
|
418
644
|
*/
|
|
419
|
-
declare function
|
|
645
|
+
declare function workloadTokenResponseSchema(vendor: string): StandardSchemaV12<Record<string, unknown>, WorkloadTokenResponse>;
|
|
420
646
|
/**
|
|
421
|
-
*
|
|
422
|
-
*
|
|
423
|
-
* @template TExtended - Type-safe custom data that consumers can add to groups
|
|
647
|
+
* Token Validation Result
|
|
424
648
|
*/
|
|
425
|
-
|
|
426
|
-
/**
|
|
427
|
-
* Required unique identifier for the group.
|
|
428
|
-
* This is the primary key for group storage.
|
|
429
|
-
*/
|
|
430
|
-
id: string;
|
|
431
|
-
/**
|
|
432
|
-
* Required human-readable name for the group.
|
|
433
|
-
*/
|
|
434
|
-
displayName: string;
|
|
649
|
+
interface TokenValidationResult {
|
|
435
650
|
/**
|
|
436
|
-
*
|
|
651
|
+
* Whether the token is valid
|
|
437
652
|
*/
|
|
438
|
-
|
|
653
|
+
valid: boolean;
|
|
439
654
|
/**
|
|
440
|
-
*
|
|
655
|
+
* The decoded and validated claims (if valid)
|
|
441
656
|
*/
|
|
442
|
-
|
|
657
|
+
claims?: JWTAssertionClaims;
|
|
443
658
|
/**
|
|
444
|
-
*
|
|
659
|
+
* Error message (if invalid)
|
|
445
660
|
*/
|
|
446
|
-
|
|
661
|
+
error?: string;
|
|
447
662
|
/**
|
|
448
|
-
*
|
|
663
|
+
* Token expiration time (if valid)
|
|
449
664
|
*/
|
|
450
|
-
|
|
451
|
-
}
|
|
665
|
+
expiresAt?: Date;
|
|
666
|
+
}
|
|
452
667
|
/**
|
|
453
|
-
*
|
|
668
|
+
* Token caching for workload identity authentication.
|
|
454
669
|
*
|
|
455
|
-
*
|
|
456
|
-
* -
|
|
457
|
-
* -
|
|
458
|
-
* -
|
|
670
|
+
* Token stores are optional but recommended for performance - they enable:
|
|
671
|
+
* - Token caching to avoid repeated token acquisition
|
|
672
|
+
* - Automatic token refresh before expiration
|
|
673
|
+
* - Reduced load on authorization servers
|
|
459
674
|
*
|
|
460
|
-
*
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
675
|
+
* ## Token Caching Strategy
|
|
676
|
+
*
|
|
677
|
+
* Unlike session stores for user authentication, workload token stores cache
|
|
678
|
+
* short-lived access tokens (typically 5 minutes) for service-to-service calls.
|
|
679
|
+
*
|
|
680
|
+
* **Default Behavior:**
|
|
681
|
+
* - Tokens cached with 5-minute TTL
|
|
682
|
+
* - Auto-refresh 60 seconds before expiration
|
|
683
|
+
* - Expired tokens automatically removed
|
|
684
|
+
*
|
|
685
|
+
* ## Performance Characteristics
|
|
686
|
+
*
|
|
687
|
+
* | Backend | Lookup Time | Use Case |
|
|
688
|
+
* |--------------|-------------|----------------------------|
|
|
689
|
+
* | InMemory | <0.00005ms | Single-server deployments |
|
|
690
|
+
* | Redis | 1-2ms | Multi-server deployments |
|
|
691
|
+
* | Database | 5-20ms | Persistent token storage |
|
|
692
|
+
*
|
|
693
|
+
* ## Example Usage
|
|
694
|
+
*
|
|
695
|
+
* ```typescript
|
|
696
|
+
* import { workload, InMemoryWorkloadTokenStore } from '@enterprisestandard/react/server';
|
|
697
|
+
*
|
|
698
|
+
* // With token caching
|
|
699
|
+
* const workloadAuth = workload({
|
|
700
|
+
* // ... other config
|
|
701
|
+
* tokenStore: new InMemoryWorkloadTokenStore(),
|
|
702
|
+
* auto_refresh: true, // Refresh before expiry
|
|
703
|
+
* });
|
|
704
|
+
*
|
|
705
|
+
* // Without token caching (fetch new token each time)
|
|
706
|
+
* const workloadAuth = workload({
|
|
707
|
+
* // ... config without tokenStore
|
|
708
|
+
* });
|
|
709
|
+
* ```
|
|
710
|
+
*/
|
|
711
|
+
/**
|
|
712
|
+
* Cached workload token data.
|
|
713
|
+
*
|
|
714
|
+
* @template TExtended - Type-safe custom data that consumers can add to cached tokens
|
|
715
|
+
*/
|
|
716
|
+
type CachedWorkloadToken<TExtended = object> = {
|
|
717
|
+
/**
|
|
718
|
+
* Workload identifier (typically SPIFFE ID).
|
|
719
|
+
* Used as the primary key for token lookup.
|
|
468
720
|
*/
|
|
469
|
-
|
|
721
|
+
workload_id: string;
|
|
470
722
|
/**
|
|
471
|
-
*
|
|
472
|
-
*
|
|
473
|
-
* @param externalId - The external identifier from the provisioning client
|
|
474
|
-
* @returns The group if found, null otherwise
|
|
723
|
+
* OAuth2 access token (Bearer token)
|
|
475
724
|
*/
|
|
476
|
-
|
|
725
|
+
access_token: string;
|
|
477
726
|
/**
|
|
478
|
-
*
|
|
479
|
-
*
|
|
480
|
-
* @param displayName - The group's display name
|
|
481
|
-
* @returns The group if found, null otherwise
|
|
727
|
+
* Token type (always "Bearer" for OAuth2)
|
|
482
728
|
*/
|
|
483
|
-
|
|
729
|
+
token_type: string;
|
|
484
730
|
/**
|
|
485
|
-
*
|
|
486
|
-
*
|
|
487
|
-
* @returns Array of all stored groups
|
|
731
|
+
* OAuth2 scopes granted for this token
|
|
488
732
|
*/
|
|
489
|
-
|
|
733
|
+
scope?: string;
|
|
490
734
|
/**
|
|
491
|
-
*
|
|
735
|
+
* Timestamp when the token expires.
|
|
736
|
+
* Used for automatic cleanup and refresh logic.
|
|
737
|
+
*/
|
|
738
|
+
expires_at: Date;
|
|
739
|
+
/**
|
|
740
|
+
* Timestamp when the token was created/cached.
|
|
741
|
+
*/
|
|
742
|
+
created_at: Date;
|
|
743
|
+
/**
|
|
744
|
+
* Optional refresh token (rarely used for workload identities)
|
|
745
|
+
*/
|
|
746
|
+
refresh_token?: string;
|
|
747
|
+
} & TExtended;
|
|
748
|
+
/**
|
|
749
|
+
* Abstract interface for workload token storage backends.
|
|
750
|
+
*
|
|
751
|
+
* Consumers can implement this interface to use different storage backends:
|
|
752
|
+
* - Redis (recommended for multi-server deployments)
|
|
753
|
+
* - Database (PostgreSQL, MySQL, etc. for persistence)
|
|
754
|
+
* - Distributed cache (Memcached, etc.)
|
|
755
|
+
* - Custom solutions
|
|
756
|
+
*
|
|
757
|
+
* @template TExtended - Type-safe custom data that consumers can add to cached tokens
|
|
758
|
+
*
|
|
759
|
+
* @example
|
|
760
|
+
* ```typescript
|
|
761
|
+
* // Custom token cache data
|
|
762
|
+
* type MyTokenData = {
|
|
763
|
+
* environment: string;
|
|
764
|
+
* region: string;
|
|
765
|
+
* };
|
|
766
|
+
*
|
|
767
|
+
* // Implement custom store with Redis
|
|
768
|
+
* class RedisWorkloadTokenStore implements WorkloadTokenStore<MyTokenData> {
|
|
769
|
+
* async set(token: CachedWorkloadToken<MyTokenData>): Promise<void> {
|
|
770
|
+
* const ttl = Math.floor((token.expires_at.getTime() - Date.now()) / 1000);
|
|
771
|
+
* await redis.setex(
|
|
772
|
+
* `workload:token:${token.workload_id}`,
|
|
773
|
+
* ttl,
|
|
774
|
+
* JSON.stringify(token)
|
|
775
|
+
* );
|
|
776
|
+
* }
|
|
777
|
+
*
|
|
778
|
+
* async get(workload_id: string): Promise<CachedWorkloadToken<MyTokenData> | null> {
|
|
779
|
+
* const data = await redis.get(`workload:token:${workload_id}`);
|
|
780
|
+
* if (!data) return null;
|
|
781
|
+
* const token = JSON.parse(data);
|
|
782
|
+
* // Convert date strings back to Date objects
|
|
783
|
+
* token.expires_at = new Date(token.expires_at);
|
|
784
|
+
* token.created_at = new Date(token.created_at);
|
|
785
|
+
* return token;
|
|
786
|
+
* }
|
|
787
|
+
*
|
|
788
|
+
* // ... other methods
|
|
789
|
+
* }
|
|
790
|
+
* ```
|
|
791
|
+
*/
|
|
792
|
+
interface WorkloadTokenStore<TExtended = object> {
|
|
793
|
+
/**
|
|
794
|
+
* Store or update a workload token in the cache.
|
|
492
795
|
*
|
|
493
|
-
*
|
|
494
|
-
|
|
796
|
+
* @param token - The token data to cache
|
|
797
|
+
*/
|
|
798
|
+
set(token: CachedWorkloadToken<TExtended>): Promise<void>;
|
|
799
|
+
/**
|
|
800
|
+
* Retrieve a cached token by workload ID.
|
|
495
801
|
*
|
|
496
|
-
* @param
|
|
802
|
+
* @param workload_id - The workload identifier (e.g., SPIFFE ID)
|
|
803
|
+
* @returns The cached token if found and not expired, null otherwise
|
|
497
804
|
*/
|
|
498
|
-
|
|
805
|
+
get(workload_id: string): Promise<CachedWorkloadToken<TExtended> | null>;
|
|
499
806
|
/**
|
|
500
|
-
* Delete a
|
|
807
|
+
* Delete a cached token by workload ID.
|
|
501
808
|
*
|
|
502
|
-
*
|
|
809
|
+
* Used when explicitly revoking tokens or clearing cache.
|
|
810
|
+
*
|
|
811
|
+
* @param workload_id - The workload identifier to remove
|
|
503
812
|
*/
|
|
504
|
-
delete(
|
|
813
|
+
delete(workload_id: string): Promise<void>;
|
|
505
814
|
/**
|
|
506
|
-
*
|
|
815
|
+
* Check if a valid (non-expired) token exists for a workload.
|
|
507
816
|
*
|
|
508
|
-
* @param
|
|
509
|
-
* @
|
|
817
|
+
* @param workload_id - The workload identifier to check
|
|
818
|
+
* @returns true if a valid token exists, false otherwise
|
|
510
819
|
*/
|
|
511
|
-
|
|
820
|
+
isValid(workload_id: string): Promise<boolean>;
|
|
512
821
|
/**
|
|
513
|
-
* Remove
|
|
822
|
+
* Remove all expired tokens from the cache.
|
|
514
823
|
*
|
|
515
|
-
*
|
|
516
|
-
* @param memberId - The member's value/id to remove
|
|
824
|
+
* Should be called periodically to prevent memory leaks.
|
|
517
825
|
*/
|
|
518
|
-
|
|
826
|
+
cleanup(): Promise<void>;
|
|
519
827
|
}
|
|
520
828
|
/**
|
|
521
|
-
* In-memory
|
|
829
|
+
* In-memory workload token store implementation using Maps.
|
|
522
830
|
*
|
|
523
831
|
* Suitable for:
|
|
524
832
|
* - Development and testing
|
|
@@ -526,790 +834,898 @@ interface GroupStore<TExtended = {}> {
|
|
|
526
834
|
* - Applications without high availability requirements
|
|
527
835
|
*
|
|
528
836
|
* NOT suitable for:
|
|
529
|
-
* - Multi-server deployments (
|
|
530
|
-
* - High availability scenarios (
|
|
837
|
+
* - Multi-server deployments (tokens not shared across instances)
|
|
838
|
+
* - High availability scenarios (tokens lost on restart)
|
|
531
839
|
* - Production applications with distributed architecture
|
|
532
840
|
*
|
|
533
|
-
* For production, implement
|
|
841
|
+
* For production multi-server deployments, implement WorkloadTokenStore with Redis.
|
|
534
842
|
*
|
|
535
|
-
* @template TExtended - Type-safe custom data that consumers can add to
|
|
843
|
+
* @template TExtended - Type-safe custom data that consumers can add to cached tokens
|
|
536
844
|
*/
|
|
537
|
-
declare class
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
get(id: string): Promise<StoredGroup<TExtended> | null>;
|
|
545
|
-
getByExternalId(externalId: string): Promise<StoredGroup<TExtended> | null>;
|
|
546
|
-
getByDisplayName(displayName: string): Promise<StoredGroup<TExtended> | null>;
|
|
547
|
-
list(): Promise<StoredGroup<TExtended>[]>;
|
|
548
|
-
upsert(group: StoredGroup<TExtended>): Promise<void>;
|
|
549
|
-
delete(id: string): Promise<void>;
|
|
550
|
-
addMember(groupId: string, member: GroupMember): Promise<void>;
|
|
551
|
-
removeMember(groupId: string, memberId: string): Promise<void>;
|
|
845
|
+
declare class InMemoryWorkloadTokenStore<TExtended = object> implements WorkloadTokenStore<TExtended> {
|
|
846
|
+
private tokens;
|
|
847
|
+
set(token: CachedWorkloadToken<TExtended>): Promise<void>;
|
|
848
|
+
get(workload_id: string): Promise<CachedWorkloadToken<TExtended> | null>;
|
|
849
|
+
delete(workload_id: string): Promise<void>;
|
|
850
|
+
isValid(workload_id: string): Promise<boolean>;
|
|
851
|
+
cleanup(): Promise<void>;
|
|
552
852
|
}
|
|
553
853
|
/**
|
|
554
|
-
*
|
|
555
|
-
* Extended by User (SSO) and EnterpriseUser (SCIM).
|
|
854
|
+
* Common fields shared across all workload authentication modes
|
|
556
855
|
*/
|
|
557
|
-
|
|
856
|
+
type WorkloadConfigBase = {
|
|
558
857
|
/**
|
|
559
|
-
*
|
|
858
|
+
* OAuth2 token endpoint URL
|
|
859
|
+
* REQUIRED for client role (token acquisition)
|
|
560
860
|
*/
|
|
561
|
-
|
|
861
|
+
tokenUrl?: string;
|
|
562
862
|
/**
|
|
563
|
-
*
|
|
863
|
+
* JWKS endpoint URL for public key retrieval
|
|
864
|
+
* REQUIRED for server role (token validation)
|
|
564
865
|
*/
|
|
565
|
-
|
|
866
|
+
jwksUri?: string;
|
|
566
867
|
/**
|
|
567
|
-
*
|
|
868
|
+
* Expected token issuer URL for validation
|
|
869
|
+
* RECOMMENDED for server role (token validation)
|
|
568
870
|
*/
|
|
569
|
-
|
|
871
|
+
issuer?: string;
|
|
570
872
|
/**
|
|
571
|
-
*
|
|
873
|
+
* Target audience for tokens
|
|
572
874
|
*/
|
|
573
|
-
|
|
875
|
+
audience?: string;
|
|
574
876
|
/**
|
|
575
|
-
*
|
|
877
|
+
* Default OAuth2 scopes (space-delimited)
|
|
576
878
|
*/
|
|
577
|
-
|
|
578
|
-
}
|
|
579
|
-
import { StandardSchemaV1 as StandardSchemaV12 } from "@standard-schema/spec";
|
|
580
|
-
/**
|
|
581
|
-
* OIDC Code Flow Callback URL Parameters
|
|
582
|
-
* @see https://openid.net/specs/openid-connect-core-1_0.html#CodeFlowAuth
|
|
583
|
-
*/
|
|
584
|
-
interface OidcCallbackParams {
|
|
879
|
+
scope?: string;
|
|
585
880
|
/**
|
|
586
|
-
*
|
|
881
|
+
* JWT assertion/token lifetime in seconds
|
|
882
|
+
* @default 300 (5 minutes)
|
|
587
883
|
*/
|
|
588
|
-
|
|
884
|
+
tokenLifetime?: number;
|
|
589
885
|
/**
|
|
590
|
-
*
|
|
591
|
-
*
|
|
886
|
+
* Refresh threshold in seconds (refresh token this many seconds before expiry)
|
|
887
|
+
* @default 60
|
|
592
888
|
*/
|
|
593
|
-
|
|
889
|
+
refreshThreshold?: number;
|
|
594
890
|
/**
|
|
595
|
-
*
|
|
891
|
+
* Optional token store for caching access tokens
|
|
596
892
|
*/
|
|
597
|
-
|
|
893
|
+
tokenStore?: WorkloadTokenStore;
|
|
598
894
|
/**
|
|
599
|
-
*
|
|
895
|
+
* Automatically refresh tokens before expiration
|
|
896
|
+
* @default true
|
|
600
897
|
*/
|
|
601
|
-
|
|
898
|
+
autoRefresh?: boolean;
|
|
602
899
|
/**
|
|
603
|
-
*
|
|
900
|
+
* Optional RFC 7009 token revocation endpoint
|
|
604
901
|
*/
|
|
605
|
-
|
|
902
|
+
revocationEndpoint?: string;
|
|
606
903
|
/**
|
|
607
|
-
*
|
|
904
|
+
* Optional handler defaults (merged with per-call overrides in `handler`)
|
|
608
905
|
*/
|
|
609
|
-
|
|
906
|
+
validateUrl?: string;
|
|
907
|
+
jwksUrl?: string;
|
|
908
|
+
refreshUrl?: string;
|
|
909
|
+
validators?: WorkloadValidators;
|
|
910
|
+
};
|
|
911
|
+
type WorkloadValidators = {
|
|
912
|
+
jwtAssertionClaims: StandardSchemaV13<unknown, JWTAssertionClaims>;
|
|
913
|
+
tokenResponse: StandardSchemaV13<unknown, WorkloadTokenResponse>;
|
|
914
|
+
};
|
|
915
|
+
/**
|
|
916
|
+
* JWT Bearer Grant (RFC 7523) Configuration
|
|
917
|
+
*
|
|
918
|
+
* Used for SPIFFE-style workload identities where services have their own
|
|
919
|
+
* cryptographic identity and sign their own JWT assertions.
|
|
920
|
+
*
|
|
921
|
+
* @example
|
|
922
|
+
* ```json
|
|
923
|
+
* {
|
|
924
|
+
* "token_url": "https://auth.example.com/oauth/token",
|
|
925
|
+
* "jwks_uri": "https://auth.example.com/.well-known/jwks.json",
|
|
926
|
+
* "workload_id": "spiffe://trust-domain/ns/service",
|
|
927
|
+
* "audience": "https://auth.example.com/oauth/token",
|
|
928
|
+
* "private_key": "-----BEGIN PRIVATE KEY-----...",
|
|
929
|
+
* "algorithm": "RS256"
|
|
930
|
+
* }
|
|
931
|
+
* ```
|
|
932
|
+
*/
|
|
933
|
+
type JwtBearerWorkloadConfig = WorkloadConfigBase & {
|
|
610
934
|
/**
|
|
611
|
-
*
|
|
612
|
-
*
|
|
935
|
+
* Workload identifier (e.g., SPIFFE ID: spiffe://trust-domain/namespace/service)
|
|
936
|
+
* REQUIRED for JWT Bearer Grant mode
|
|
613
937
|
*/
|
|
614
|
-
|
|
615
|
-
|
|
938
|
+
workloadId: string;
|
|
939
|
+
/**
|
|
940
|
+
* PEM-encoded private key for signing JWT assertions
|
|
941
|
+
* REQUIRED for client role in JWT Bearer Grant mode
|
|
942
|
+
*/
|
|
943
|
+
privateKey: string;
|
|
944
|
+
/**
|
|
945
|
+
* Key ID (kid) to include in JWT header for key rotation support
|
|
946
|
+
*/
|
|
947
|
+
keyId?: string;
|
|
948
|
+
/**
|
|
949
|
+
* JWT signing algorithm
|
|
950
|
+
* @default 'RS256'
|
|
951
|
+
*/
|
|
952
|
+
algorithm?: "RS256" | "RS384" | "RS512" | "ES256" | "ES384" | "ES512";
|
|
953
|
+
};
|
|
616
954
|
/**
|
|
617
|
-
*
|
|
618
|
-
*
|
|
619
|
-
*
|
|
955
|
+
* OAuth2 Client Credentials Configuration
|
|
956
|
+
*
|
|
957
|
+
* Standard OAuth2 Client Credentials Grant (RFC 6749 Section 4.4).
|
|
958
|
+
* Used with identity providers like Keycloak for service-to-service authentication.
|
|
959
|
+
*
|
|
960
|
+
* @example
|
|
961
|
+
* ```json
|
|
962
|
+
* {
|
|
963
|
+
* "token_url": "https://sso.example.com/realms/myrealm/protocol/openid-connect/token",
|
|
964
|
+
* "jwks_uri": "https://sso.example.com/realms/myrealm/protocol/openid-connect/certs",
|
|
965
|
+
* "client_id": "my-service",
|
|
966
|
+
* "client_secret": "secret-from-idp",
|
|
967
|
+
* "issuer": "https://sso.example.com/realms/myrealm",
|
|
968
|
+
* "scope": "api:read api:write"
|
|
969
|
+
* }
|
|
970
|
+
* ```
|
|
620
971
|
*/
|
|
621
|
-
|
|
972
|
+
type ClientCredentialsWorkloadConfig = WorkloadConfigBase & {
|
|
973
|
+
/**
|
|
974
|
+
* OAuth2 client identifier registered with the authorization server
|
|
975
|
+
* REQUIRED for Client Credentials mode
|
|
976
|
+
*/
|
|
977
|
+
clientId: string;
|
|
978
|
+
/**
|
|
979
|
+
* OAuth2 client secret
|
|
980
|
+
* REQUIRED for Client Credentials mode
|
|
981
|
+
*/
|
|
982
|
+
clientSecret: string;
|
|
983
|
+
};
|
|
622
984
|
/**
|
|
623
|
-
*
|
|
985
|
+
* Server-Only Workload Configuration
|
|
986
|
+
*
|
|
987
|
+
* Used when a service only needs to validate incoming workload tokens,
|
|
988
|
+
* not acquire tokens for outbound calls. Requires only jwks_uri for
|
|
989
|
+
* public key retrieval.
|
|
990
|
+
*
|
|
991
|
+
* Note: jwksUri and issuer are optional in TypeScript (since they come from vault)
|
|
992
|
+
* but are required at runtime and validated by standardSchema validators.
|
|
993
|
+
*
|
|
994
|
+
* @example
|
|
995
|
+
* ```json
|
|
996
|
+
* {
|
|
997
|
+
* "jwks_uri": "https://sso.example.com/realms/myrealm/protocol/openid-connect/certs",
|
|
998
|
+
* "issuer": "https://sso.example.com/realms/myrealm"
|
|
999
|
+
* }
|
|
1000
|
+
* ```
|
|
624
1001
|
*/
|
|
625
|
-
|
|
626
|
-
|
|
627
|
-
|
|
628
|
-
|
|
629
|
-
|
|
630
|
-
|
|
1002
|
+
type ServerOnlyWorkloadConfig = WorkloadConfigBase & {
|
|
1003
|
+
/**
|
|
1004
|
+
* JWKS endpoint URL for public key retrieval
|
|
1005
|
+
* REQUIRED at runtime (validated by standardSchema), optional in TypeScript (comes from vault)
|
|
1006
|
+
*/
|
|
1007
|
+
jwksUri?: string;
|
|
1008
|
+
};
|
|
1009
|
+
/**
|
|
1010
|
+
* Workload Identity Authentication Configuration
|
|
1011
|
+
*
|
|
1012
|
+
* Union type supporting multiple authentication modes. The mode is automatically
|
|
1013
|
+
* detected based on which fields are present:
|
|
1014
|
+
*
|
|
1015
|
+
* - **JWT Bearer Grant**: Requires `workload_id` + `private_key`
|
|
1016
|
+
* - **Client Credentials**: Requires `client_id` + `client_secret`
|
|
1017
|
+
* - **Server-Only**: Only `jwks_uri` (and optionally `issuer`) for token validation
|
|
1018
|
+
*
|
|
1019
|
+
* The developer uses the same API regardless of mode - the library handles the details.
|
|
1020
|
+
*/
|
|
1021
|
+
type WorkloadConfig = JwtBearerWorkloadConfig | ClientCredentialsWorkloadConfig | ServerOnlyWorkloadConfig;
|
|
1022
|
+
/**
|
|
1023
|
+
* Workload Identity extracted from validated tokens
|
|
1024
|
+
*/
|
|
1025
|
+
type WorkloadIdentity = {
|
|
1026
|
+
/**
|
|
1027
|
+
* Workload identifier (for JWT Bearer Grant tokens)
|
|
1028
|
+
*/
|
|
1029
|
+
workloadId?: string;
|
|
1030
|
+
/**
|
|
1031
|
+
* Client identifier (for OAuth2 Client Credentials tokens)
|
|
1032
|
+
*/
|
|
1033
|
+
clientId?: string;
|
|
1034
|
+
/**
|
|
1035
|
+
* Granted scopes
|
|
1036
|
+
*/
|
|
631
1037
|
scope?: string;
|
|
632
|
-
|
|
633
|
-
|
|
634
|
-
|
|
635
|
-
|
|
1038
|
+
/**
|
|
1039
|
+
* Full JWT claims from the token
|
|
1040
|
+
*/
|
|
1041
|
+
claims: JWTAssertionClaims;
|
|
1042
|
+
};
|
|
636
1043
|
/**
|
|
637
|
-
*
|
|
638
|
-
* @param vendor - The name of the vendor creating this schema
|
|
639
|
-
* @returns A StandardSchemaV1 instance for Token Response validation
|
|
1044
|
+
* Workload Identity Authentication Interface
|
|
640
1045
|
*/
|
|
641
|
-
|
|
1046
|
+
type Workload = {
|
|
1047
|
+
config: WorkloadConfig;
|
|
1048
|
+
getToken: (scope?: string) => Promise<string>;
|
|
1049
|
+
refreshToken: (scope?: string) => Promise<WorkloadTokenResponse>;
|
|
1050
|
+
generateJWTAssertion: (scope?: string) => Promise<string>;
|
|
1051
|
+
revokeToken: (token: string) => Promise<void>;
|
|
1052
|
+
validateToken: (token: string) => Promise<TokenValidationResult>;
|
|
1053
|
+
getWorkloadIdentity: (request: Request) => Promise<WorkloadIdentity | undefined>;
|
|
1054
|
+
parseJWT: (token: string) => Promise<JWTAssertionClaims>;
|
|
1055
|
+
handler: (request: Request) => Promise<Response>;
|
|
1056
|
+
};
|
|
1057
|
+
declare function workload(validators: WorkloadValidators, fromVault?: Partial<WorkloadConfig>, fromCode?: Partial<WorkloadConfig>): Workload | undefined;
|
|
1058
|
+
type CIAMConfig<
|
|
1059
|
+
TMagicLinkData = {},
|
|
1060
|
+
TUserData = {}
|
|
1061
|
+
> = {
|
|
1062
|
+
/**
|
|
1063
|
+
* Magic link store for storing magic link tokens
|
|
1064
|
+
*/
|
|
1065
|
+
magicLinkStore?: MagicLinkStore<TMagicLinkData>;
|
|
1066
|
+
/**
|
|
1067
|
+
* Default TTL for magic links in seconds
|
|
1068
|
+
* @default 3600 (1 hour)
|
|
1069
|
+
*/
|
|
1070
|
+
magicLinkTtl?: number;
|
|
1071
|
+
/**
|
|
1072
|
+
* URL path for generating magic links (POST endpoint)
|
|
1073
|
+
*/
|
|
1074
|
+
magicLinkUrl?: string;
|
|
1075
|
+
/**
|
|
1076
|
+
* URL path for validating magic links (GET endpoint)
|
|
1077
|
+
*/
|
|
1078
|
+
magicLinkLoginUrl?: string;
|
|
1079
|
+
/**
|
|
1080
|
+
* Landing URL after successful magic link authentication
|
|
1081
|
+
*/
|
|
1082
|
+
landingUrl?: string;
|
|
1083
|
+
/**
|
|
1084
|
+
* Error URL for failed magic link authentication
|
|
1085
|
+
*/
|
|
1086
|
+
errorUrl?: string;
|
|
1087
|
+
/**
|
|
1088
|
+
* Cookie prefix for CIAM cookies
|
|
1089
|
+
* @default 'es.ciam'
|
|
1090
|
+
*/
|
|
1091
|
+
cookiesPrefix?: string;
|
|
1092
|
+
/**
|
|
1093
|
+
* Cookie path
|
|
1094
|
+
* @default '/'
|
|
1095
|
+
*/
|
|
1096
|
+
cookiesPath?: string;
|
|
1097
|
+
/**
|
|
1098
|
+
* Secure cookies (HTTPS only)
|
|
1099
|
+
* @default true
|
|
1100
|
+
*/
|
|
1101
|
+
cookiesSecure?: boolean;
|
|
1102
|
+
/**
|
|
1103
|
+
* SameSite cookie attribute
|
|
1104
|
+
* @default 'Strict'
|
|
1105
|
+
*/
|
|
1106
|
+
cookiesSameSite?: "Strict" | "Lax";
|
|
1107
|
+
/**
|
|
1108
|
+
* Optional identifier for CIAM cookies (used in prefix).
|
|
1109
|
+
* When set, cookiesPrefix defaults to `es.ciam.${ciamId}`.
|
|
1110
|
+
*/
|
|
1111
|
+
ciamId?: string;
|
|
1112
|
+
/**
|
|
1113
|
+
* Signing key for CIAM JWT tokens.
|
|
1114
|
+
*
|
|
1115
|
+
* Generate using one of these methods:
|
|
1116
|
+
* - OpenSSL: openssl rand -base64 64
|
|
1117
|
+
* - Node.js: node -e "console.log(require('crypto').randomBytes(64).toString('base64'))"
|
|
1118
|
+
* - Python: python3 -c "import secrets; print(secrets.token_urlsafe(64))"
|
|
1119
|
+
*
|
|
1120
|
+
* Store in Vault under ciam.signingKey or provide in code config.
|
|
1121
|
+
* REQUIRED - will throw error during initialization if missing.
|
|
1122
|
+
*/
|
|
1123
|
+
signingKey?: string;
|
|
1124
|
+
/**
|
|
1125
|
+
* Server-side session store for CIAM sessions (required for backchannel logout).
|
|
1126
|
+
*/
|
|
1127
|
+
sessionStore?: SessionStore;
|
|
1128
|
+
/**
|
|
1129
|
+
* Session validation strategy.
|
|
1130
|
+
* @default 'always'
|
|
1131
|
+
*/
|
|
1132
|
+
sessionValidation?: "always" | "refresh-only" | "disabled";
|
|
1133
|
+
/**
|
|
1134
|
+
* Logout URL (GET endpoint)
|
|
1135
|
+
*/
|
|
1136
|
+
logoutUrl?: string;
|
|
1137
|
+
/**
|
|
1138
|
+
* Back-channel logout URL (POST endpoint)
|
|
1139
|
+
*/
|
|
1140
|
+
logoutBackChannelUrl?: string;
|
|
1141
|
+
/**
|
|
1142
|
+
* Optional user store for persisting user profiles from magic link authentication.
|
|
1143
|
+
* When configured, users are automatically stored/updated on each login.
|
|
1144
|
+
*/
|
|
1145
|
+
userStore?: UserStore<TUserData>;
|
|
1146
|
+
/**
|
|
1147
|
+
* Enable Just-In-Time (JIT) user provisioning.
|
|
1148
|
+
* When enabled, new users are automatically created in the userStore on their first login.
|
|
1149
|
+
* When disabled (default), only existing users in the userStore are updated on login.
|
|
1150
|
+
* Requires userStore to be configured.
|
|
1151
|
+
* @default false
|
|
1152
|
+
*/
|
|
1153
|
+
enableJitUserProvisioning?: boolean;
|
|
1154
|
+
/**
|
|
1155
|
+
* Session expiration time in seconds (for cookies)
|
|
1156
|
+
* @default 86400 (24 hours)
|
|
1157
|
+
*/
|
|
1158
|
+
sessionTtl?: number;
|
|
1159
|
+
};
|
|
1160
|
+
type CIAM<
|
|
1161
|
+
TMagicLinkData = {},
|
|
1162
|
+
TUserData = {}
|
|
1163
|
+
> = {
|
|
1164
|
+
config: CIAMConfig<TMagicLinkData, TUserData>;
|
|
1165
|
+
getUser: (request: Request) => Promise<User | undefined>;
|
|
1166
|
+
getRequiredUser: (request: Request) => Promise<User>;
|
|
1167
|
+
logout: (request: Request) => Promise<Response>;
|
|
1168
|
+
logoutBackChannel: (request: Request) => Promise<Response>;
|
|
1169
|
+
handler: (request: Request) => Promise<Response>;
|
|
1170
|
+
};
|
|
1171
|
+
declare function ciam<
|
|
1172
|
+
TMagicLinkData = {},
|
|
1173
|
+
TUserData = {}
|
|
1174
|
+
>(fromVault?: Partial<CIAMConfig<TMagicLinkData, TUserData>>, fromCode?: Partial<CIAMConfig<TMagicLinkData, TUserData>>, workload?: {
|
|
1175
|
+
getWorkloadIdentity: (request: Request) => Promise<WorkloadIdentity | undefined>;
|
|
1176
|
+
}): CIAM<TMagicLinkData, TUserData> | undefined;
|
|
1177
|
+
import { StandardSchemaV1 as StandardSchemaV15 } from "@standard-schema/spec";
|
|
1178
|
+
import { StandardSchemaV1 as StandardSchemaV14 } from "@standard-schema/spec";
|
|
642
1179
|
/**
|
|
643
|
-
*
|
|
1180
|
+
* SCIM 2.0 User Resource
|
|
1181
|
+
* @see https://datatracker.ietf.org/doc/html/rfc7643#section-4.1
|
|
644
1182
|
*/
|
|
645
|
-
interface IdTokenClaims {
|
|
646
|
-
iss?: string;
|
|
647
|
-
aud?: string;
|
|
648
|
-
exp?: number;
|
|
649
|
-
iat?: number;
|
|
650
|
-
sub?: string;
|
|
651
|
-
sid?: string;
|
|
652
|
-
name?: string;
|
|
653
|
-
email?: string;
|
|
654
|
-
preferred_username?: string;
|
|
655
|
-
picture?: string;
|
|
656
|
-
[key: string]: unknown;
|
|
657
|
-
}
|
|
658
1183
|
/**
|
|
659
|
-
*
|
|
660
|
-
* @param vendor - The name of the vendor creating this schema
|
|
661
|
-
* @returns A StandardSchemaV1 instance for ID Token Claims validation
|
|
1184
|
+
* SCIM Name sub-attribute
|
|
662
1185
|
*/
|
|
663
|
-
|
|
1186
|
+
interface Name {
|
|
1187
|
+
/**
|
|
1188
|
+
* The full name, including all middle names, titles, and suffixes as appropriate
|
|
1189
|
+
*/
|
|
1190
|
+
formatted?: string;
|
|
1191
|
+
/**
|
|
1192
|
+
* The family name of the User, or last name
|
|
1193
|
+
*/
|
|
1194
|
+
familyName?: string;
|
|
1195
|
+
/**
|
|
1196
|
+
* The given name of the User, or first name
|
|
1197
|
+
*/
|
|
1198
|
+
givenName?: string;
|
|
1199
|
+
/**
|
|
1200
|
+
* The middle name(s) of the User
|
|
1201
|
+
*/
|
|
1202
|
+
middleName?: string;
|
|
1203
|
+
/**
|
|
1204
|
+
* The honorific prefix(es) of the User, or title
|
|
1205
|
+
*/
|
|
1206
|
+
honorificPrefix?: string;
|
|
1207
|
+
/**
|
|
1208
|
+
* The honorific suffix(es) of the User, or suffix
|
|
1209
|
+
*/
|
|
1210
|
+
honorificSuffix?: string;
|
|
1211
|
+
}
|
|
664
1212
|
/**
|
|
665
|
-
*
|
|
666
|
-
* Extends BaseUser with SSO-specific data.
|
|
1213
|
+
* SCIM Email sub-attribute
|
|
667
1214
|
*/
|
|
668
|
-
interface
|
|
1215
|
+
interface Email {
|
|
1216
|
+
/**
|
|
1217
|
+
* The email address value
|
|
1218
|
+
*/
|
|
1219
|
+
value: string;
|
|
1220
|
+
/**
|
|
1221
|
+
* A human-readable name, primarily used for display purposes
|
|
1222
|
+
*/
|
|
1223
|
+
display?: string;
|
|
1224
|
+
/**
|
|
1225
|
+
* A label indicating the attribute's function (e.g., "work" or "home")
|
|
1226
|
+
*/
|
|
1227
|
+
type?: string;
|
|
669
1228
|
/**
|
|
670
|
-
*
|
|
1229
|
+
* A Boolean value indicating the 'primary' or preferred attribute value
|
|
671
1230
|
*/
|
|
672
|
-
|
|
673
|
-
/**
|
|
674
|
-
* ID Token claims from the identity provider
|
|
675
|
-
*/
|
|
676
|
-
profile: IdTokenClaims;
|
|
677
|
-
/**
|
|
678
|
-
* Tenant/organization information
|
|
679
|
-
*/
|
|
680
|
-
tenant: {
|
|
681
|
-
id: string;
|
|
682
|
-
name: string;
|
|
683
|
-
};
|
|
684
|
-
/**
|
|
685
|
-
* OAuth scopes granted
|
|
686
|
-
*/
|
|
687
|
-
scope?: string;
|
|
688
|
-
/**
|
|
689
|
-
* Token type (typically "Bearer")
|
|
690
|
-
*/
|
|
691
|
-
tokenType: string;
|
|
692
|
-
/**
|
|
693
|
-
* Session state from the identity provider
|
|
694
|
-
*/
|
|
695
|
-
sessionState?: string;
|
|
696
|
-
/**
|
|
697
|
-
* Token expiration time
|
|
698
|
-
*/
|
|
699
|
-
expires: Date;
|
|
700
|
-
};
|
|
1231
|
+
primary?: boolean;
|
|
701
1232
|
}
|
|
702
1233
|
/**
|
|
703
|
-
*
|
|
704
|
-
*
|
|
705
|
-
* Extends the SSO User type with:
|
|
706
|
-
* - Required `id` (the `sub` claim from the IdP)
|
|
707
|
-
* - Timestamps for tracking when users were first seen and last updated
|
|
708
|
-
* - Optional custom extended data
|
|
709
|
-
*
|
|
710
|
-
* @template TExtended - Type-safe custom data that consumers can add to users
|
|
1234
|
+
* SCIM Phone Number sub-attribute
|
|
711
1235
|
*/
|
|
712
|
-
|
|
1236
|
+
interface PhoneNumber {
|
|
713
1237
|
/**
|
|
714
|
-
*
|
|
715
|
-
* This is the primary key for user storage.
|
|
1238
|
+
* The phone number value
|
|
716
1239
|
*/
|
|
717
|
-
|
|
1240
|
+
value: string;
|
|
718
1241
|
/**
|
|
719
|
-
*
|
|
1242
|
+
* A human-readable name, primarily used for display purposes
|
|
720
1243
|
*/
|
|
721
|
-
|
|
1244
|
+
display?: string;
|
|
722
1245
|
/**
|
|
723
|
-
*
|
|
1246
|
+
* A label indicating the attribute's function (e.g., "work", "home", "mobile")
|
|
724
1247
|
*/
|
|
725
|
-
|
|
726
|
-
|
|
1248
|
+
type?: string;
|
|
1249
|
+
/**
|
|
1250
|
+
* A Boolean value indicating the 'primary' or preferred attribute value
|
|
1251
|
+
*/
|
|
1252
|
+
primary?: boolean;
|
|
1253
|
+
}
|
|
727
1254
|
/**
|
|
728
|
-
*
|
|
729
|
-
*
|
|
730
|
-
* Consumers can implement this interface to use different storage backends:
|
|
731
|
-
* - In-memory (for development/testing)
|
|
732
|
-
* - Redis (for production with fast lookups)
|
|
733
|
-
* - Database (PostgreSQL, MySQL, etc.)
|
|
734
|
-
*
|
|
735
|
-
* @template TExtended - Type-safe custom data that consumers can add to users
|
|
736
|
-
*
|
|
737
|
-
* @example
|
|
738
|
-
* ```typescript
|
|
739
|
-
* // Custom user data
|
|
740
|
-
* type MyUserData = {
|
|
741
|
-
* department: string;
|
|
742
|
-
* roles: string[];
|
|
743
|
-
* };
|
|
744
|
-
*
|
|
745
|
-
* // Implement custom store
|
|
746
|
-
* class RedisUserStore implements UserStore<MyUserData> {
|
|
747
|
-
* async get(sub: string): Promise<StoredUser<MyUserData> | null> {
|
|
748
|
-
* const data = await redis.get(`user:${sub}`);
|
|
749
|
-
* return data ? JSON.parse(data) : null;
|
|
750
|
-
* }
|
|
751
|
-
* // ... other methods
|
|
752
|
-
* }
|
|
753
|
-
* ```
|
|
1255
|
+
* SCIM Address sub-attribute
|
|
754
1256
|
*/
|
|
755
|
-
interface
|
|
1257
|
+
interface Address {
|
|
756
1258
|
/**
|
|
757
|
-
*
|
|
758
|
-
*
|
|
759
|
-
* @param sub - The user's unique identifier from the IdP
|
|
760
|
-
* @returns The user if found, null otherwise
|
|
1259
|
+
* The full mailing address, formatted for display
|
|
761
1260
|
*/
|
|
762
|
-
|
|
1261
|
+
formatted?: string;
|
|
763
1262
|
/**
|
|
764
|
-
*
|
|
765
|
-
*
|
|
766
|
-
* @param email - The user's email address
|
|
767
|
-
* @returns The user if found, null otherwise
|
|
1263
|
+
* The full street address component
|
|
768
1264
|
*/
|
|
769
|
-
|
|
1265
|
+
streetAddress?: string;
|
|
770
1266
|
/**
|
|
771
|
-
*
|
|
772
|
-
*
|
|
773
|
-
* @param userName - The user's username
|
|
774
|
-
* @returns The user if found, null otherwise
|
|
1267
|
+
* The city or locality component
|
|
775
1268
|
*/
|
|
776
|
-
|
|
1269
|
+
locality?: string;
|
|
777
1270
|
/**
|
|
778
|
-
*
|
|
779
|
-
*
|
|
780
|
-
* If a user with the same `id` (sub) exists, it will be updated.
|
|
781
|
-
* Otherwise, a new user will be created.
|
|
782
|
-
*
|
|
783
|
-
* @param user - The user data to store
|
|
1271
|
+
* The state or region component
|
|
784
1272
|
*/
|
|
785
|
-
|
|
1273
|
+
region?: string;
|
|
786
1274
|
/**
|
|
787
|
-
*
|
|
788
|
-
*
|
|
789
|
-
* @param sub - The user's unique identifier to delete
|
|
1275
|
+
* The zip code or postal code component
|
|
790
1276
|
*/
|
|
791
|
-
|
|
1277
|
+
postalCode?: string;
|
|
1278
|
+
/**
|
|
1279
|
+
* The country name component
|
|
1280
|
+
*/
|
|
1281
|
+
country?: string;
|
|
1282
|
+
/**
|
|
1283
|
+
* A label indicating the attribute's function (e.g., "work" or "home")
|
|
1284
|
+
*/
|
|
1285
|
+
type?: string;
|
|
1286
|
+
/**
|
|
1287
|
+
* A Boolean value indicating the 'primary' or preferred attribute value
|
|
1288
|
+
*/
|
|
1289
|
+
primary?: boolean;
|
|
792
1290
|
}
|
|
793
1291
|
/**
|
|
794
|
-
*
|
|
795
|
-
*
|
|
796
|
-
* Suitable for:
|
|
797
|
-
* - Development and testing
|
|
798
|
-
* - Single-server deployments
|
|
799
|
-
* - Applications without high availability requirements
|
|
800
|
-
*
|
|
801
|
-
* NOT suitable for:
|
|
802
|
-
* - Multi-server deployments (users not shared)
|
|
803
|
-
* - High availability scenarios (users lost on restart)
|
|
804
|
-
* - Production applications with distributed architecture
|
|
805
|
-
*
|
|
806
|
-
* For production, implement UserStore with Redis or a database.
|
|
807
|
-
*
|
|
808
|
-
* @template TExtended - Type-safe custom data that consumers can add to users
|
|
1292
|
+
* SCIM Group reference (used within User resources)
|
|
809
1293
|
*/
|
|
810
|
-
|
|
811
|
-
/**
|
|
812
|
-
|
|
813
|
-
|
|
814
|
-
|
|
815
|
-
/**
|
|
816
|
-
|
|
817
|
-
|
|
818
|
-
|
|
819
|
-
|
|
820
|
-
|
|
821
|
-
|
|
1294
|
+
interface Group {
|
|
1295
|
+
/**
|
|
1296
|
+
* The identifier of the User's group
|
|
1297
|
+
*/
|
|
1298
|
+
value: string;
|
|
1299
|
+
/**
|
|
1300
|
+
* The URI of the corresponding 'Group' resource
|
|
1301
|
+
*/
|
|
1302
|
+
$ref?: string;
|
|
1303
|
+
/**
|
|
1304
|
+
* A human-readable name, primarily used for display purposes
|
|
1305
|
+
*/
|
|
1306
|
+
display?: string;
|
|
1307
|
+
/**
|
|
1308
|
+
* A label indicating the attribute's function (e.g., "direct" or "indirect")
|
|
1309
|
+
*/
|
|
1310
|
+
type?: string;
|
|
822
1311
|
}
|
|
823
|
-
import { StandardSchemaV1 as StandardSchemaV14 } from "@standard-schema/spec";
|
|
824
|
-
import { StandardSchemaV1 as StandardSchemaV13 } from "@standard-schema/spec";
|
|
825
1312
|
/**
|
|
826
|
-
*
|
|
827
|
-
* @see https://datatracker.ietf.org/doc/html/rfc7523
|
|
828
|
-
* @see https://datatracker.ietf.org/doc/html/rfc9068
|
|
1313
|
+
* SCIM Group Member reference
|
|
829
1314
|
*/
|
|
830
|
-
interface
|
|
1315
|
+
interface GroupMember {
|
|
831
1316
|
/**
|
|
832
|
-
*
|
|
1317
|
+
* The identifier of the member (User or Group)
|
|
833
1318
|
*/
|
|
834
|
-
|
|
1319
|
+
value: string;
|
|
835
1320
|
/**
|
|
836
|
-
*
|
|
1321
|
+
* The URI of the corresponding member resource
|
|
837
1322
|
*/
|
|
838
|
-
|
|
1323
|
+
$ref?: string;
|
|
839
1324
|
/**
|
|
840
|
-
*
|
|
841
|
-
* Note: Required for JWT assertions, but may be absent in OAuth2 access tokens
|
|
1325
|
+
* A human-readable name of the member
|
|
842
1326
|
*/
|
|
843
|
-
|
|
1327
|
+
display?: string;
|
|
844
1328
|
/**
|
|
845
|
-
*
|
|
1329
|
+
* The type of the member (e.g., "User" or "Group")
|
|
846
1330
|
*/
|
|
847
|
-
|
|
1331
|
+
type?: "User" | "Group";
|
|
1332
|
+
}
|
|
1333
|
+
/**
|
|
1334
|
+
* SCIM 2.0 Group Resource
|
|
1335
|
+
* @see https://datatracker.ietf.org/doc/html/rfc7643#section-4.2
|
|
1336
|
+
*/
|
|
1337
|
+
interface GroupResource {
|
|
848
1338
|
/**
|
|
849
|
-
* REQUIRED.
|
|
1339
|
+
* REQUIRED. The schemas attribute
|
|
850
1340
|
*/
|
|
851
|
-
|
|
1341
|
+
schemas?: string[];
|
|
852
1342
|
/**
|
|
853
|
-
*
|
|
854
|
-
|
|
1343
|
+
* Unique identifier for the Group, assigned by the service provider
|
|
1344
|
+
*/
|
|
1345
|
+
id?: string;
|
|
1346
|
+
/**
|
|
1347
|
+
* External identifier from the provisioning client
|
|
1348
|
+
*/
|
|
1349
|
+
externalId?: string;
|
|
1350
|
+
/**
|
|
1351
|
+
* Resource metadata
|
|
1352
|
+
*/
|
|
1353
|
+
meta?: {
|
|
1354
|
+
resourceType?: string;
|
|
1355
|
+
created?: string;
|
|
1356
|
+
lastModified?: string;
|
|
1357
|
+
location?: string;
|
|
1358
|
+
version?: string;
|
|
1359
|
+
};
|
|
1360
|
+
/**
|
|
1361
|
+
* REQUIRED. A human-readable name for the Group
|
|
1362
|
+
*/
|
|
1363
|
+
displayName: string;
|
|
1364
|
+
/**
|
|
1365
|
+
* A list of members of the Group
|
|
1366
|
+
*/
|
|
1367
|
+
members?: GroupMember[];
|
|
1368
|
+
}
|
|
1369
|
+
/**
|
|
1370
|
+
* SCIM Role
|
|
1371
|
+
*/
|
|
1372
|
+
interface Role {
|
|
1373
|
+
/**
|
|
1374
|
+
* The value of the role
|
|
1375
|
+
*/
|
|
1376
|
+
value: string;
|
|
1377
|
+
/**
|
|
1378
|
+
* A human-readable name, primarily used for display purposes
|
|
855
1379
|
*/
|
|
856
|
-
|
|
1380
|
+
display?: string;
|
|
857
1381
|
/**
|
|
858
|
-
*
|
|
1382
|
+
* A label indicating the attribute's function
|
|
859
1383
|
*/
|
|
860
|
-
|
|
1384
|
+
type?: string;
|
|
861
1385
|
/**
|
|
862
|
-
*
|
|
1386
|
+
* A Boolean value indicating the 'primary' or preferred attribute value
|
|
863
1387
|
*/
|
|
864
|
-
|
|
1388
|
+
primary?: boolean;
|
|
865
1389
|
}
|
|
866
1390
|
/**
|
|
867
|
-
*
|
|
868
|
-
* @param vendor - The name of the vendor creating this schema
|
|
869
|
-
* @returns A StandardSchemaV1 instance for JWT Assertion Claims validation
|
|
870
|
-
*/
|
|
871
|
-
declare function jwtAssertionClaimsSchema(vendor: string): StandardSchemaV13<Record<string, unknown>, JWTAssertionClaims>;
|
|
872
|
-
/**
|
|
873
|
-
* Workload Token Response from OAuth2 token endpoint
|
|
874
|
-
* @see https://datatracker.ietf.org/doc/html/rfc6749#section-5.1
|
|
1391
|
+
* SCIM X509 Certificate
|
|
875
1392
|
*/
|
|
876
|
-
interface
|
|
1393
|
+
interface X509Certificate {
|
|
877
1394
|
/**
|
|
878
|
-
*
|
|
1395
|
+
* The value of the X.509 certificate
|
|
879
1396
|
*/
|
|
880
|
-
|
|
1397
|
+
value: string;
|
|
881
1398
|
/**
|
|
882
|
-
*
|
|
1399
|
+
* A human-readable name, primarily used for display purposes
|
|
883
1400
|
*/
|
|
884
|
-
|
|
1401
|
+
display?: string;
|
|
885
1402
|
/**
|
|
886
|
-
*
|
|
1403
|
+
* A label indicating the attribute's function
|
|
887
1404
|
*/
|
|
888
|
-
|
|
1405
|
+
type?: string;
|
|
889
1406
|
/**
|
|
890
|
-
*
|
|
1407
|
+
* A Boolean value indicating the 'primary' or preferred attribute value
|
|
891
1408
|
*/
|
|
892
|
-
|
|
1409
|
+
primary?: boolean;
|
|
1410
|
+
}
|
|
1411
|
+
/**
|
|
1412
|
+
* SCIM Enterprise User Extension
|
|
1413
|
+
* @see https://datatracker.ietf.org/doc/html/rfc7643#section-4.3
|
|
1414
|
+
*/
|
|
1415
|
+
interface EnterpriseExtension {
|
|
893
1416
|
/**
|
|
894
|
-
*
|
|
1417
|
+
* Numeric or alphanumeric identifier assigned to a person
|
|
895
1418
|
*/
|
|
896
|
-
|
|
1419
|
+
employeeNumber?: string;
|
|
897
1420
|
/**
|
|
898
|
-
*
|
|
1421
|
+
* Identifies the name of a cost center
|
|
899
1422
|
*/
|
|
900
|
-
|
|
901
|
-
}
|
|
902
|
-
/**
|
|
903
|
-
* Creates a StandardSchemaV1 for validating Workload Token Responses.
|
|
904
|
-
* @param vendor - The name of the vendor creating this schema
|
|
905
|
-
* @returns A StandardSchemaV1 instance for Workload Token Response validation
|
|
906
|
-
*/
|
|
907
|
-
declare function workloadTokenResponseSchema(vendor: string): StandardSchemaV13<Record<string, unknown>, WorkloadTokenResponse>;
|
|
908
|
-
/**
|
|
909
|
-
* Token Validation Result
|
|
910
|
-
*/
|
|
911
|
-
interface TokenValidationResult {
|
|
1423
|
+
costCenter?: string;
|
|
912
1424
|
/**
|
|
913
|
-
*
|
|
1425
|
+
* Identifies the name of an organization
|
|
914
1426
|
*/
|
|
915
|
-
|
|
1427
|
+
organization?: string;
|
|
916
1428
|
/**
|
|
917
|
-
*
|
|
1429
|
+
* Identifies the name of a division
|
|
918
1430
|
*/
|
|
919
|
-
|
|
1431
|
+
division?: string;
|
|
920
1432
|
/**
|
|
921
|
-
*
|
|
1433
|
+
* Identifies the name of a department
|
|
922
1434
|
*/
|
|
923
|
-
|
|
1435
|
+
department?: string;
|
|
924
1436
|
/**
|
|
925
|
-
*
|
|
1437
|
+
* The user's manager
|
|
926
1438
|
*/
|
|
927
|
-
|
|
1439
|
+
manager?: {
|
|
1440
|
+
/**
|
|
1441
|
+
* The "id" of the SCIM resource representing the User's manager
|
|
1442
|
+
*/
|
|
1443
|
+
value?: string;
|
|
1444
|
+
/**
|
|
1445
|
+
* The URI of the SCIM resource representing the User's manager
|
|
1446
|
+
*/
|
|
1447
|
+
$ref?: string;
|
|
1448
|
+
/**
|
|
1449
|
+
* The displayName of the User's manager
|
|
1450
|
+
*/
|
|
1451
|
+
displayName?: string;
|
|
1452
|
+
};
|
|
928
1453
|
}
|
|
929
1454
|
/**
|
|
930
|
-
*
|
|
931
|
-
*
|
|
932
|
-
* Token stores are optional but recommended for performance - they enable:
|
|
933
|
-
* - Token caching to avoid repeated token acquisition
|
|
934
|
-
* - Automatic token refresh before expiration
|
|
935
|
-
* - Reduced load on authorization servers
|
|
936
|
-
*
|
|
937
|
-
* ## Token Caching Strategy
|
|
938
|
-
*
|
|
939
|
-
* Unlike session stores for user authentication, workload token stores cache
|
|
940
|
-
* short-lived access tokens (typically 5 minutes) for service-to-service calls.
|
|
941
|
-
*
|
|
942
|
-
* **Default Behavior:**
|
|
943
|
-
* - Tokens cached with 5-minute TTL
|
|
944
|
-
* - Auto-refresh 60 seconds before expiration
|
|
945
|
-
* - Expired tokens automatically removed
|
|
946
|
-
*
|
|
947
|
-
* ## Performance Characteristics
|
|
948
|
-
*
|
|
949
|
-
* | Backend | Lookup Time | Use Case |
|
|
950
|
-
* |--------------|-------------|----------------------------|
|
|
951
|
-
* | InMemory | <0.00005ms | Single-server deployments |
|
|
952
|
-
* | Redis | 1-2ms | Multi-server deployments |
|
|
953
|
-
* | Database | 5-20ms | Persistent token storage |
|
|
954
|
-
*
|
|
955
|
-
* ## Example Usage
|
|
956
|
-
*
|
|
957
|
-
* ```typescript
|
|
958
|
-
* import { workload, InMemoryWorkloadTokenStore } from '@enterprisestandard/react/server';
|
|
959
|
-
*
|
|
960
|
-
* // With token caching
|
|
961
|
-
* const workloadAuth = workload({
|
|
962
|
-
* // ... other config
|
|
963
|
-
* tokenStore: new InMemoryWorkloadTokenStore(),
|
|
964
|
-
* auto_refresh: true, // Refresh before expiry
|
|
965
|
-
* });
|
|
966
|
-
*
|
|
967
|
-
* // Without token caching (fetch new token each time)
|
|
968
|
-
* const workloadAuth = workload({
|
|
969
|
-
* // ... config without tokenStore
|
|
970
|
-
* });
|
|
971
|
-
* ```
|
|
972
|
-
*/
|
|
973
|
-
/**
|
|
974
|
-
* Cached workload token data.
|
|
975
|
-
*
|
|
976
|
-
* @template TExtended - Type-safe custom data that consumers can add to cached tokens
|
|
1455
|
+
* SCIM User Resource
|
|
977
1456
|
*/
|
|
978
|
-
|
|
1457
|
+
interface User2 {
|
|
979
1458
|
/**
|
|
980
|
-
*
|
|
981
|
-
* Used as the primary key for token lookup.
|
|
1459
|
+
* REQUIRED. Unique identifier for the User, typically from the provider
|
|
982
1460
|
*/
|
|
983
|
-
|
|
1461
|
+
id?: string;
|
|
984
1462
|
/**
|
|
985
|
-
*
|
|
1463
|
+
* REQUIRED. A unique identifier for a SCIM resource as defined by the service provider
|
|
986
1464
|
*/
|
|
987
|
-
|
|
1465
|
+
externalId?: string;
|
|
988
1466
|
/**
|
|
989
|
-
*
|
|
1467
|
+
* Resource metadata
|
|
990
1468
|
*/
|
|
991
|
-
|
|
1469
|
+
meta?: {
|
|
1470
|
+
resourceType?: string;
|
|
1471
|
+
created?: string;
|
|
1472
|
+
lastModified?: string;
|
|
1473
|
+
location?: string;
|
|
1474
|
+
version?: string;
|
|
1475
|
+
};
|
|
992
1476
|
/**
|
|
993
|
-
*
|
|
1477
|
+
* REQUIRED. Unique identifier for the User, typically used for login
|
|
994
1478
|
*/
|
|
995
|
-
|
|
1479
|
+
userName: string;
|
|
996
1480
|
/**
|
|
997
|
-
*
|
|
998
|
-
* Used for automatic cleanup and refresh logic.
|
|
1481
|
+
* The components of the user's name
|
|
999
1482
|
*/
|
|
1000
|
-
|
|
1483
|
+
name?: Name;
|
|
1001
1484
|
/**
|
|
1002
|
-
*
|
|
1485
|
+
* The name of the User, suitable for display to end-users
|
|
1003
1486
|
*/
|
|
1004
|
-
|
|
1487
|
+
displayName?: string;
|
|
1005
1488
|
/**
|
|
1006
|
-
*
|
|
1489
|
+
* The casual way to address the user
|
|
1007
1490
|
*/
|
|
1008
|
-
|
|
1009
|
-
} & TExtended;
|
|
1010
|
-
/**
|
|
1011
|
-
* Abstract interface for workload token storage backends.
|
|
1012
|
-
*
|
|
1013
|
-
* Consumers can implement this interface to use different storage backends:
|
|
1014
|
-
* - Redis (recommended for multi-server deployments)
|
|
1015
|
-
* - Database (PostgreSQL, MySQL, etc. for persistence)
|
|
1016
|
-
* - Distributed cache (Memcached, etc.)
|
|
1017
|
-
* - Custom solutions
|
|
1018
|
-
*
|
|
1019
|
-
* @template TExtended - Type-safe custom data that consumers can add to cached tokens
|
|
1020
|
-
*
|
|
1021
|
-
* @example
|
|
1022
|
-
* ```typescript
|
|
1023
|
-
* // Custom token cache data
|
|
1024
|
-
* type MyTokenData = {
|
|
1025
|
-
* environment: string;
|
|
1026
|
-
* region: string;
|
|
1027
|
-
* };
|
|
1028
|
-
*
|
|
1029
|
-
* // Implement custom store with Redis
|
|
1030
|
-
* class RedisWorkloadTokenStore implements WorkloadTokenStore<MyTokenData> {
|
|
1031
|
-
* async set(token: CachedWorkloadToken<MyTokenData>): Promise<void> {
|
|
1032
|
-
* const ttl = Math.floor((token.expires_at.getTime() - Date.now()) / 1000);
|
|
1033
|
-
* await redis.setex(
|
|
1034
|
-
* `workload:token:${token.workload_id}`,
|
|
1035
|
-
* ttl,
|
|
1036
|
-
* JSON.stringify(token)
|
|
1037
|
-
* );
|
|
1038
|
-
* }
|
|
1039
|
-
*
|
|
1040
|
-
* async get(workload_id: string): Promise<CachedWorkloadToken<MyTokenData> | null> {
|
|
1041
|
-
* const data = await redis.get(`workload:token:${workload_id}`);
|
|
1042
|
-
* if (!data) return null;
|
|
1043
|
-
* const token = JSON.parse(data);
|
|
1044
|
-
* // Convert date strings back to Date objects
|
|
1045
|
-
* token.expires_at = new Date(token.expires_at);
|
|
1046
|
-
* token.created_at = new Date(token.created_at);
|
|
1047
|
-
* return token;
|
|
1048
|
-
* }
|
|
1049
|
-
*
|
|
1050
|
-
* // ... other methods
|
|
1051
|
-
* }
|
|
1052
|
-
* ```
|
|
1053
|
-
*/
|
|
1054
|
-
interface WorkloadTokenStore<TExtended = object> {
|
|
1491
|
+
nickName?: string;
|
|
1055
1492
|
/**
|
|
1056
|
-
*
|
|
1057
|
-
*
|
|
1058
|
-
* @param token - The token data to cache
|
|
1493
|
+
* A fully qualified URL pointing to a page representing the User's online profile
|
|
1059
1494
|
*/
|
|
1060
|
-
|
|
1495
|
+
profileUrl?: string;
|
|
1061
1496
|
/**
|
|
1062
|
-
*
|
|
1063
|
-
*
|
|
1064
|
-
* @param workload_id - The workload identifier (e.g., SPIFFE ID)
|
|
1065
|
-
* @returns The cached token if found and not expired, null otherwise
|
|
1497
|
+
* The user's title, such as "Vice President"
|
|
1066
1498
|
*/
|
|
1067
|
-
|
|
1499
|
+
title?: string;
|
|
1068
1500
|
/**
|
|
1069
|
-
*
|
|
1070
|
-
*
|
|
1071
|
-
* Used when explicitly revoking tokens or clearing cache.
|
|
1072
|
-
*
|
|
1073
|
-
* @param workload_id - The workload identifier to remove
|
|
1501
|
+
* Used to identify the relationship between the organization and the user
|
|
1074
1502
|
*/
|
|
1075
|
-
|
|
1503
|
+
userType?: string;
|
|
1076
1504
|
/**
|
|
1077
|
-
*
|
|
1078
|
-
|
|
1079
|
-
|
|
1080
|
-
|
|
1505
|
+
* Indicates the User's preferred written or spoken language
|
|
1506
|
+
*/
|
|
1507
|
+
preferredLanguage?: string;
|
|
1508
|
+
/**
|
|
1509
|
+
* Used to indicate the User's default location for purposes of localizing items such as currency
|
|
1510
|
+
*/
|
|
1511
|
+
locale?: string;
|
|
1512
|
+
/**
|
|
1513
|
+
* The User's time zone in the "Olson" time zone database format
|
|
1081
1514
|
*/
|
|
1082
|
-
|
|
1515
|
+
timezone?: string;
|
|
1083
1516
|
/**
|
|
1084
|
-
*
|
|
1085
|
-
*
|
|
1086
|
-
* Should be called periodically to prevent memory leaks.
|
|
1517
|
+
* A Boolean value indicating the User's administrative status
|
|
1087
1518
|
*/
|
|
1088
|
-
|
|
1089
|
-
}
|
|
1090
|
-
/**
|
|
1091
|
-
* In-memory workload token store implementation using Maps.
|
|
1092
|
-
*
|
|
1093
|
-
* Suitable for:
|
|
1094
|
-
* - Development and testing
|
|
1095
|
-
* - Single-server deployments
|
|
1096
|
-
* - Applications without high availability requirements
|
|
1097
|
-
*
|
|
1098
|
-
* NOT suitable for:
|
|
1099
|
-
* - Multi-server deployments (tokens not shared across instances)
|
|
1100
|
-
* - High availability scenarios (tokens lost on restart)
|
|
1101
|
-
* - Production applications with distributed architecture
|
|
1102
|
-
*
|
|
1103
|
-
* For production multi-server deployments, implement WorkloadTokenStore with Redis.
|
|
1104
|
-
*
|
|
1105
|
-
* @template TExtended - Type-safe custom data that consumers can add to cached tokens
|
|
1106
|
-
*/
|
|
1107
|
-
declare class InMemoryWorkloadTokenStore<TExtended = object> implements WorkloadTokenStore<TExtended> {
|
|
1108
|
-
private tokens;
|
|
1109
|
-
set(token: CachedWorkloadToken<TExtended>): Promise<void>;
|
|
1110
|
-
get(workload_id: string): Promise<CachedWorkloadToken<TExtended> | null>;
|
|
1111
|
-
delete(workload_id: string): Promise<void>;
|
|
1112
|
-
isValid(workload_id: string): Promise<boolean>;
|
|
1113
|
-
cleanup(): Promise<void>;
|
|
1114
|
-
}
|
|
1115
|
-
/**
|
|
1116
|
-
* Common fields shared across all workload authentication modes
|
|
1117
|
-
*/
|
|
1118
|
-
type WorkloadConfigBase = {
|
|
1519
|
+
active?: boolean;
|
|
1119
1520
|
/**
|
|
1120
|
-
*
|
|
1121
|
-
* REQUIRED for client role (token acquisition)
|
|
1521
|
+
* The User's cleartext password
|
|
1122
1522
|
*/
|
|
1123
|
-
|
|
1523
|
+
password?: string;
|
|
1124
1524
|
/**
|
|
1125
|
-
*
|
|
1126
|
-
* REQUIRED for server role (token validation)
|
|
1525
|
+
* Email addresses for the user
|
|
1127
1526
|
*/
|
|
1128
|
-
|
|
1527
|
+
emails?: Email[];
|
|
1129
1528
|
/**
|
|
1130
|
-
*
|
|
1131
|
-
* RECOMMENDED for server role (token validation)
|
|
1529
|
+
* Phone numbers for the User
|
|
1132
1530
|
*/
|
|
1133
|
-
|
|
1531
|
+
phoneNumbers?: PhoneNumber[];
|
|
1134
1532
|
/**
|
|
1135
|
-
*
|
|
1533
|
+
* Instant messaging addresses for the User
|
|
1136
1534
|
*/
|
|
1137
|
-
|
|
1535
|
+
ims?: Array<{
|
|
1536
|
+
value: string;
|
|
1537
|
+
display?: string;
|
|
1538
|
+
type?: string;
|
|
1539
|
+
primary?: boolean;
|
|
1540
|
+
}>;
|
|
1138
1541
|
/**
|
|
1139
|
-
*
|
|
1542
|
+
* URLs of photos of the User
|
|
1140
1543
|
*/
|
|
1141
|
-
|
|
1544
|
+
photos?: Array<{
|
|
1545
|
+
value: string;
|
|
1546
|
+
display?: string;
|
|
1547
|
+
type?: string;
|
|
1548
|
+
primary?: boolean;
|
|
1549
|
+
}>;
|
|
1142
1550
|
/**
|
|
1143
|
-
*
|
|
1144
|
-
* @default 300 (5 minutes)
|
|
1551
|
+
* Physical mailing addresses for this User
|
|
1145
1552
|
*/
|
|
1146
|
-
|
|
1553
|
+
addresses?: Address[];
|
|
1147
1554
|
/**
|
|
1148
|
-
*
|
|
1149
|
-
* @default 60
|
|
1555
|
+
* A list of groups to which the user belongs
|
|
1150
1556
|
*/
|
|
1151
|
-
|
|
1557
|
+
groups?: Group[];
|
|
1152
1558
|
/**
|
|
1153
|
-
*
|
|
1559
|
+
* A list of entitlements for the User
|
|
1154
1560
|
*/
|
|
1155
|
-
|
|
1561
|
+
entitlements?: Array<{
|
|
1562
|
+
value: string;
|
|
1563
|
+
display?: string;
|
|
1564
|
+
type?: string;
|
|
1565
|
+
primary?: boolean;
|
|
1566
|
+
}>;
|
|
1156
1567
|
/**
|
|
1157
|
-
*
|
|
1158
|
-
* @default true
|
|
1568
|
+
* A list of roles for the User
|
|
1159
1569
|
*/
|
|
1160
|
-
|
|
1570
|
+
roles?: Role[];
|
|
1161
1571
|
/**
|
|
1162
|
-
*
|
|
1572
|
+
* A list of certificates issued to the User
|
|
1163
1573
|
*/
|
|
1164
|
-
|
|
1574
|
+
x509Certificates?: X509Certificate[];
|
|
1165
1575
|
/**
|
|
1166
|
-
*
|
|
1576
|
+
* Enterprise User Extension
|
|
1167
1577
|
*/
|
|
1168
|
-
|
|
1169
|
-
|
|
1170
|
-
|
|
1171
|
-
|
|
1172
|
-
|
|
1173
|
-
|
|
1174
|
-
jwtAssertionClaims: StandardSchemaV14<unknown, JWTAssertionClaims>;
|
|
1175
|
-
tokenResponse: StandardSchemaV14<unknown, WorkloadTokenResponse>;
|
|
1176
|
-
};
|
|
1578
|
+
"urn:ietf:params:scim:schemas:extension:enterprise:2.0:User"?: EnterpriseExtension;
|
|
1579
|
+
/**
|
|
1580
|
+
* REQUIRED. The schemas attribute is an array of Strings which allows introspection of the supported schema version
|
|
1581
|
+
*/
|
|
1582
|
+
schemas?: string[];
|
|
1583
|
+
}
|
|
1177
1584
|
/**
|
|
1178
|
-
*
|
|
1179
|
-
*
|
|
1180
|
-
*
|
|
1181
|
-
|
|
1585
|
+
* Creates a StandardSchemaV1 for validating SCIM User resources.
|
|
1586
|
+
* @param vendor - The name of the vendor creating this schema
|
|
1587
|
+
* @returns A StandardSchemaV1 instance for SCIM User resources
|
|
1588
|
+
*/
|
|
1589
|
+
declare function userSchema(vendor: string): StandardSchemaV14<Record<string, unknown>, User2>;
|
|
1590
|
+
/**
|
|
1591
|
+
* Creates a StandardSchemaV1 for validating SCIM Group resources.
|
|
1592
|
+
* @param vendor - The name of the vendor creating this schema
|
|
1593
|
+
* @returns A StandardSchemaV1 instance for SCIM Group resources
|
|
1594
|
+
*/
|
|
1595
|
+
declare function groupResourceSchema(vendor: string): StandardSchemaV14<Record<string, unknown>, GroupResource>;
|
|
1596
|
+
/**
|
|
1597
|
+
* Stored group data with required id and tracking metadata.
|
|
1182
1598
|
*
|
|
1183
|
-
* @
|
|
1184
|
-
* ```json
|
|
1185
|
-
* {
|
|
1186
|
-
* "token_url": "https://auth.example.com/oauth/token",
|
|
1187
|
-
* "jwks_uri": "https://auth.example.com/.well-known/jwks.json",
|
|
1188
|
-
* "workload_id": "spiffe://trust-domain/ns/service",
|
|
1189
|
-
* "audience": "https://auth.example.com/oauth/token",
|
|
1190
|
-
* "private_key": "-----BEGIN PRIVATE KEY-----...",
|
|
1191
|
-
* "algorithm": "RS256"
|
|
1192
|
-
* }
|
|
1193
|
-
* ```
|
|
1599
|
+
* @template TExtended - Type-safe custom data that consumers can add to groups
|
|
1194
1600
|
*/
|
|
1195
|
-
type
|
|
1601
|
+
type StoredGroup<TExtended = {}> = {
|
|
1196
1602
|
/**
|
|
1197
|
-
*
|
|
1198
|
-
*
|
|
1603
|
+
* Required unique identifier for the group.
|
|
1604
|
+
* This is the primary key for group storage.
|
|
1199
1605
|
*/
|
|
1200
|
-
|
|
1606
|
+
id: string;
|
|
1201
1607
|
/**
|
|
1202
|
-
*
|
|
1203
|
-
* REQUIRED for client role in JWT Bearer Grant mode
|
|
1608
|
+
* Required human-readable name for the group.
|
|
1204
1609
|
*/
|
|
1205
|
-
|
|
1610
|
+
displayName: string;
|
|
1206
1611
|
/**
|
|
1207
|
-
*
|
|
1612
|
+
* Optional external identifier from provisioning client.
|
|
1208
1613
|
*/
|
|
1209
|
-
|
|
1614
|
+
externalId?: string;
|
|
1210
1615
|
/**
|
|
1211
|
-
*
|
|
1212
|
-
* @default 'RS256'
|
|
1616
|
+
* List of members in the group.
|
|
1213
1617
|
*/
|
|
1214
|
-
|
|
1215
|
-
};
|
|
1216
|
-
/**
|
|
1217
|
-
* OAuth2 Client Credentials Configuration
|
|
1218
|
-
*
|
|
1219
|
-
* Standard OAuth2 Client Credentials Grant (RFC 6749 Section 4.4).
|
|
1220
|
-
* Used with identity providers like Keycloak for service-to-service authentication.
|
|
1221
|
-
*
|
|
1222
|
-
* @example
|
|
1223
|
-
* ```json
|
|
1224
|
-
* {
|
|
1225
|
-
* "token_url": "https://sso.example.com/realms/myrealm/protocol/openid-connect/token",
|
|
1226
|
-
* "jwks_uri": "https://sso.example.com/realms/myrealm/protocol/openid-connect/certs",
|
|
1227
|
-
* "client_id": "my-service",
|
|
1228
|
-
* "client_secret": "secret-from-idp",
|
|
1229
|
-
* "issuer": "https://sso.example.com/realms/myrealm",
|
|
1230
|
-
* "scope": "api:read api:write"
|
|
1231
|
-
* }
|
|
1232
|
-
* ```
|
|
1233
|
-
*/
|
|
1234
|
-
type ClientCredentialsWorkloadConfig = WorkloadConfigBase & {
|
|
1618
|
+
members?: GroupMember[];
|
|
1235
1619
|
/**
|
|
1236
|
-
*
|
|
1237
|
-
* REQUIRED for Client Credentials mode
|
|
1620
|
+
* Timestamp when the group was first stored.
|
|
1238
1621
|
*/
|
|
1239
|
-
|
|
1622
|
+
createdAt: Date;
|
|
1240
1623
|
/**
|
|
1241
|
-
*
|
|
1242
|
-
* REQUIRED for Client Credentials mode
|
|
1624
|
+
* Timestamp when the group was last updated.
|
|
1243
1625
|
*/
|
|
1244
|
-
|
|
1245
|
-
};
|
|
1246
|
-
/**
|
|
1247
|
-
* Server-Only Workload Configuration
|
|
1248
|
-
*
|
|
1249
|
-
* Used when a service only needs to validate incoming workload tokens,
|
|
1250
|
-
* not acquire tokens for outbound calls. Requires only jwks_uri for
|
|
1251
|
-
* public key retrieval.
|
|
1252
|
-
*
|
|
1253
|
-
* @example
|
|
1254
|
-
* ```json
|
|
1255
|
-
* {
|
|
1256
|
-
* "jwks_uri": "https://sso.example.com/realms/myrealm/protocol/openid-connect/certs",
|
|
1257
|
-
* "issuer": "https://sso.example.com/realms/myrealm"
|
|
1258
|
-
* }
|
|
1259
|
-
* ```
|
|
1260
|
-
*/
|
|
1261
|
-
type ServerOnlyWorkloadConfig = WorkloadConfigBase & {
|
|
1262
|
-
jwksUri: string;
|
|
1263
|
-
};
|
|
1626
|
+
updatedAt: Date;
|
|
1627
|
+
} & TExtended;
|
|
1264
1628
|
/**
|
|
1265
|
-
*
|
|
1266
|
-
*
|
|
1267
|
-
* Union type supporting multiple authentication modes. The mode is automatically
|
|
1268
|
-
* detected based on which fields are present:
|
|
1629
|
+
* Abstract interface for group storage backends.
|
|
1269
1630
|
*
|
|
1270
|
-
*
|
|
1271
|
-
* -
|
|
1272
|
-
* -
|
|
1631
|
+
* Consumers can implement this interface to use different storage backends:
|
|
1632
|
+
* - In-memory (for development/testing)
|
|
1633
|
+
* - Redis (for production with fast lookups)
|
|
1634
|
+
* - Database (PostgreSQL, MySQL, etc.)
|
|
1273
1635
|
*
|
|
1274
|
-
*
|
|
1275
|
-
*/
|
|
1276
|
-
type WorkloadConfig = JwtBearerWorkloadConfig | ClientCredentialsWorkloadConfig | ServerOnlyWorkloadConfig;
|
|
1277
|
-
/**
|
|
1278
|
-
* Workload Identity extracted from validated tokens
|
|
1636
|
+
* @template TExtended - Type-safe custom data that consumers can add to groups
|
|
1279
1637
|
*/
|
|
1280
|
-
|
|
1638
|
+
interface GroupStore<TExtended = {}> {
|
|
1639
|
+
/**
|
|
1640
|
+
* Retrieve a group by its unique identifier.
|
|
1641
|
+
*
|
|
1642
|
+
* @param id - The group's unique identifier
|
|
1643
|
+
* @returns The group if found, null otherwise
|
|
1644
|
+
*/
|
|
1645
|
+
get(id: string): Promise<StoredGroup<TExtended> | null>;
|
|
1646
|
+
/**
|
|
1647
|
+
* Retrieve a group by its external identifier.
|
|
1648
|
+
*
|
|
1649
|
+
* @param externalId - The external identifier from the provisioning client
|
|
1650
|
+
* @returns The group if found, null otherwise
|
|
1651
|
+
*/
|
|
1652
|
+
getByExternalId(externalId: string): Promise<StoredGroup<TExtended> | null>;
|
|
1653
|
+
/**
|
|
1654
|
+
* Retrieve a group by its display name.
|
|
1655
|
+
*
|
|
1656
|
+
* @param displayName - The group's display name
|
|
1657
|
+
* @returns The group if found, null otherwise
|
|
1658
|
+
*/
|
|
1659
|
+
getByDisplayName(displayName: string): Promise<StoredGroup<TExtended> | null>;
|
|
1660
|
+
/**
|
|
1661
|
+
* List all groups in the store.
|
|
1662
|
+
*
|
|
1663
|
+
* @returns Array of all stored groups
|
|
1664
|
+
*/
|
|
1665
|
+
list(): Promise<StoredGroup<TExtended>[]>;
|
|
1281
1666
|
/**
|
|
1282
|
-
*
|
|
1667
|
+
* Create or update a group in the store.
|
|
1668
|
+
*
|
|
1669
|
+
* If a group with the same `id` exists, it will be updated.
|
|
1670
|
+
* Otherwise, a new group will be created.
|
|
1671
|
+
*
|
|
1672
|
+
* @param group - The group data to store
|
|
1283
1673
|
*/
|
|
1284
|
-
|
|
1674
|
+
upsert(group: StoredGroup<TExtended>): Promise<void>;
|
|
1285
1675
|
/**
|
|
1286
|
-
*
|
|
1676
|
+
* Delete a group by its unique identifier.
|
|
1677
|
+
*
|
|
1678
|
+
* @param id - The group's unique identifier to delete
|
|
1287
1679
|
*/
|
|
1288
|
-
|
|
1680
|
+
delete(id: string): Promise<void>;
|
|
1289
1681
|
/**
|
|
1290
|
-
*
|
|
1682
|
+
* Add a member to a group.
|
|
1683
|
+
*
|
|
1684
|
+
* @param groupId - The group's unique identifier
|
|
1685
|
+
* @param member - The member to add
|
|
1291
1686
|
*/
|
|
1292
|
-
|
|
1687
|
+
addMember(groupId: string, member: GroupMember): Promise<void>;
|
|
1293
1688
|
/**
|
|
1294
|
-
*
|
|
1689
|
+
* Remove a member from a group.
|
|
1690
|
+
*
|
|
1691
|
+
* @param groupId - The group's unique identifier
|
|
1692
|
+
* @param memberId - The member's value/id to remove
|
|
1295
1693
|
*/
|
|
1296
|
-
|
|
1297
|
-
}
|
|
1694
|
+
removeMember(groupId: string, memberId: string): Promise<void>;
|
|
1695
|
+
}
|
|
1298
1696
|
/**
|
|
1299
|
-
*
|
|
1697
|
+
* In-memory group store implementation using Maps.
|
|
1698
|
+
*
|
|
1699
|
+
* Suitable for:
|
|
1700
|
+
* - Development and testing
|
|
1701
|
+
* - Single-server deployments
|
|
1702
|
+
* - Applications without high availability requirements
|
|
1703
|
+
*
|
|
1704
|
+
* NOT suitable for:
|
|
1705
|
+
* - Multi-server deployments (groups not shared)
|
|
1706
|
+
* - High availability scenarios (groups lost on restart)
|
|
1707
|
+
* - Production applications with distributed architecture
|
|
1708
|
+
*
|
|
1709
|
+
* For production, implement GroupStore with Redis or a database.
|
|
1710
|
+
*
|
|
1711
|
+
* @template TExtended - Type-safe custom data that consumers can add to groups
|
|
1300
1712
|
*/
|
|
1301
|
-
|
|
1302
|
-
|
|
1303
|
-
|
|
1304
|
-
|
|
1305
|
-
|
|
1306
|
-
|
|
1307
|
-
|
|
1308
|
-
|
|
1309
|
-
|
|
1310
|
-
|
|
1311
|
-
|
|
1312
|
-
|
|
1713
|
+
declare class InMemoryGroupStore<TExtended = {}> implements GroupStore<TExtended> {
|
|
1714
|
+
/** Primary storage: id -> group */
|
|
1715
|
+
private groups;
|
|
1716
|
+
/** Secondary index: externalId -> id */
|
|
1717
|
+
private externalIdIndex;
|
|
1718
|
+
/** Secondary index: displayName (lowercase) -> id */
|
|
1719
|
+
private displayNameIndex;
|
|
1720
|
+
get(id: string): Promise<StoredGroup<TExtended> | null>;
|
|
1721
|
+
getByExternalId(externalId: string): Promise<StoredGroup<TExtended> | null>;
|
|
1722
|
+
getByDisplayName(displayName: string): Promise<StoredGroup<TExtended> | null>;
|
|
1723
|
+
list(): Promise<StoredGroup<TExtended>[]>;
|
|
1724
|
+
upsert(group: StoredGroup<TExtended>): Promise<void>;
|
|
1725
|
+
delete(id: string): Promise<void>;
|
|
1726
|
+
addMember(groupId: string, member: GroupMember): Promise<void>;
|
|
1727
|
+
removeMember(groupId: string, memberId: string): Promise<void>;
|
|
1728
|
+
}
|
|
1313
1729
|
/**
|
|
1314
1730
|
* SCIM Error response structure
|
|
1315
1731
|
*/
|
|
@@ -1382,7 +1798,7 @@ type IAMConfig = {
|
|
|
1382
1798
|
groupsUrl?: string;
|
|
1383
1799
|
};
|
|
1384
1800
|
type IAMValidators = {
|
|
1385
|
-
user: StandardSchemaV15<unknown,
|
|
1801
|
+
user: StandardSchemaV15<unknown, User2>;
|
|
1386
1802
|
group: StandardSchemaV15<unknown, GroupResource>;
|
|
1387
1803
|
};
|
|
1388
1804
|
/**
|
|
@@ -1473,7 +1889,7 @@ type IAM = IAMConfig & {
|
|
|
1473
1889
|
* Create a new user/account in the external IAM provider
|
|
1474
1890
|
* Only available when `url` is configured.
|
|
1475
1891
|
*/
|
|
1476
|
-
createUser?: (user:
|
|
1892
|
+
createUser?: (user: User2, options?: CreateUserOptions) => Promise<ScimResult<User2>>;
|
|
1477
1893
|
/**
|
|
1478
1894
|
* Get the configured external SCIM base URL
|
|
1479
1895
|
*/
|
|
@@ -1511,184 +1927,6 @@ type IAM = IAMConfig & {
|
|
|
1511
1927
|
*/
|
|
1512
1928
|
declare function iam(validators: IAMValidators, workload?: Workload, fromVault?: Partial<IAMConfig>, fromCode?: Partial<IAMConfig>): IAM | undefined;
|
|
1513
1929
|
import { StandardSchemaV1 as StandardSchemaV16 } from "@standard-schema/spec";
|
|
1514
|
-
/**
|
|
1515
|
-
* Session management for tracking user sessions and enabling backchannel logout.
|
|
1516
|
-
*
|
|
1517
|
-
* Session stores are optional - the package works with JWT cookies alone.
|
|
1518
|
-
* Sessions are only required for backchannel logout functionality.
|
|
1519
|
-
*
|
|
1520
|
-
* ## Session Validation Strategies
|
|
1521
|
-
*
|
|
1522
|
-
* When using a session store, you can configure when sessions are validated:
|
|
1523
|
-
*
|
|
1524
|
-
* ### 'always' (default)
|
|
1525
|
-
* Validates session on every authenticated request.
|
|
1526
|
-
* - **Security**: Maximum - immediate session revocation
|
|
1527
|
-
* - **Performance**: InMemory ~0.00005ms, Redis ~1-2ms per request
|
|
1528
|
-
* - **Backchannel Logout**: Takes effect immediately
|
|
1529
|
-
* - **Use when**: Security is paramount, using InMemory or Redis backend
|
|
1530
|
-
*
|
|
1531
|
-
* ### 'refresh-only'
|
|
1532
|
-
* Validates session only during token refresh (typically every 5-15 minutes).
|
|
1533
|
-
* - **Security**: Good - 5-15 minute revocation window
|
|
1534
|
-
* - **Performance**: 99% reduction in session lookups
|
|
1535
|
-
* - **Backchannel Logout**: Takes effect within token TTL (5-15 min)
|
|
1536
|
-
* - **Use when**: Performance is critical AND delayed revocation is acceptable
|
|
1537
|
-
* - **WARNING**: Compromised sessions remain valid until next refresh
|
|
1538
|
-
*
|
|
1539
|
-
* ### 'disabled'
|
|
1540
|
-
* Never validates sessions against the store.
|
|
1541
|
-
* - **Security**: None - backchannel logout doesn't work
|
|
1542
|
-
* - **Performance**: No overhead
|
|
1543
|
-
* - **Use when**: Cookie-only mode without session store
|
|
1544
|
-
* - **WARNING**: Do not use with sessionStore configured
|
|
1545
|
-
*
|
|
1546
|
-
* ## Performance Characteristics
|
|
1547
|
-
*
|
|
1548
|
-
* | Backend | Lookup Time | Impact on Request | Recommendation |
|
|
1549
|
-
* |--------------|-------------|-------------------|------------------------|
|
|
1550
|
-
* | InMemory | <0.00005ms | Negligible | Use 'always' |
|
|
1551
|
-
* | Redis | 1-2ms | 2-4% increase | Use 'always' or test |
|
|
1552
|
-
* | Database | 5-20ms | 10-40% increase | Use Redis cache layer |
|
|
1553
|
-
*
|
|
1554
|
-
* ## Example Usage
|
|
1555
|
-
*
|
|
1556
|
-
* ```typescript
|
|
1557
|
-
* import { sso, InMemorySessionStore } from '@enterprisestandard/react/server';
|
|
1558
|
-
*
|
|
1559
|
-
* // Maximum security (default)
|
|
1560
|
-
* const secure = sso({
|
|
1561
|
-
* // ... other config
|
|
1562
|
-
* sessionStore: new InMemorySessionStore(),
|
|
1563
|
-
* session_validation: 'always', // Immediate revocation
|
|
1564
|
-
* });
|
|
1565
|
-
*
|
|
1566
|
-
* // High performance
|
|
1567
|
-
* const fast = sso({
|
|
1568
|
-
* // ... other config
|
|
1569
|
-
* sessionStore: new InMemorySessionStore(),
|
|
1570
|
-
* session_validation: {
|
|
1571
|
-
* strategy: 'refresh-only' // 5-15 min revocation delay
|
|
1572
|
-
* }
|
|
1573
|
-
* });
|
|
1574
|
-
* ```
|
|
1575
|
-
*/
|
|
1576
|
-
/**
|
|
1577
|
-
* Core session data tracked for each authenticated user session.
|
|
1578
|
-
*
|
|
1579
|
-
* @template TExtended - Type-safe custom data that consumers can add to sessions
|
|
1580
|
-
*/
|
|
1581
|
-
type Session<TExtended = {}> = {
|
|
1582
|
-
/**
|
|
1583
|
-
* Session ID from the Identity Provider (from `sid` claim in ID token).
|
|
1584
|
-
* This is the unique identifier for the session.
|
|
1585
|
-
*/
|
|
1586
|
-
sid: string;
|
|
1587
|
-
/**
|
|
1588
|
-
* Subject identifier (user ID) from the Identity Provider.
|
|
1589
|
-
* From the `sub` claim in the ID token.
|
|
1590
|
-
*/
|
|
1591
|
-
sub: string;
|
|
1592
|
-
/**
|
|
1593
|
-
* Timestamp when the session was created.
|
|
1594
|
-
*/
|
|
1595
|
-
createdAt: Date;
|
|
1596
|
-
/**
|
|
1597
|
-
* Timestamp of the last activity in this session.
|
|
1598
|
-
* Can be updated to track session activity.
|
|
1599
|
-
*/
|
|
1600
|
-
lastActivityAt: Date;
|
|
1601
|
-
/**
|
|
1602
|
-
* Allow consumers to add runtime data to sessions.
|
|
1603
|
-
*/
|
|
1604
|
-
[key: string]: unknown;
|
|
1605
|
-
} & TExtended;
|
|
1606
|
-
/**
|
|
1607
|
-
* Abstract interface for session storage backends.
|
|
1608
|
-
*
|
|
1609
|
-
* Consumers can implement this interface to use different storage backends:
|
|
1610
|
-
* - Redis
|
|
1611
|
-
* - Database (PostgreSQL, MySQL, etc.)
|
|
1612
|
-
* - Distributed cache
|
|
1613
|
-
* - Custom solutions
|
|
1614
|
-
*
|
|
1615
|
-
* @template TExtended - Type-safe custom data that consumers can add to sessions
|
|
1616
|
-
*
|
|
1617
|
-
* @example
|
|
1618
|
-
* ```typescript
|
|
1619
|
-
* // Custom session data
|
|
1620
|
-
* type MySessionData = {
|
|
1621
|
-
* ipAddress: string;
|
|
1622
|
-
* userAgent: string;
|
|
1623
|
-
* };
|
|
1624
|
-
*
|
|
1625
|
-
* // Implement custom store
|
|
1626
|
-
* class RedisSessionStore implements SessionStore<MySessionData> {
|
|
1627
|
-
* async create(session: Session<MySessionData>): Promise<void> {
|
|
1628
|
-
* await redis.set(`session:${session.sid}`, JSON.stringify(session));
|
|
1629
|
-
* }
|
|
1630
|
-
* // ... other methods
|
|
1631
|
-
* }
|
|
1632
|
-
* ```
|
|
1633
|
-
*/
|
|
1634
|
-
interface SessionStore<TExtended = {}> {
|
|
1635
|
-
/**
|
|
1636
|
-
* Create a new session in the store.
|
|
1637
|
-
*
|
|
1638
|
-
* @param session - The session data to store
|
|
1639
|
-
* @throws Error if session with same sid already exists
|
|
1640
|
-
*/
|
|
1641
|
-
create(session: Session<TExtended>): Promise<void>;
|
|
1642
|
-
/**
|
|
1643
|
-
* Retrieve a session by its IdP session ID (sid).
|
|
1644
|
-
*
|
|
1645
|
-
* @param sid - The session.sid from the Identity Provider
|
|
1646
|
-
* @returns The session if found, null otherwise
|
|
1647
|
-
*/
|
|
1648
|
-
get(sid: string): Promise<Session<TExtended> | null>;
|
|
1649
|
-
/**
|
|
1650
|
-
* Update an existing session with partial data.
|
|
1651
|
-
*
|
|
1652
|
-
* Commonly used to update lastActivityAt or add custom fields.
|
|
1653
|
-
*
|
|
1654
|
-
* @param sid - The session.sid to update
|
|
1655
|
-
* @param data - Partial session data to merge
|
|
1656
|
-
* @throws Error if session not found
|
|
1657
|
-
*/
|
|
1658
|
-
update(sid: string, data: Partial<Session<TExtended>>): Promise<void>;
|
|
1659
|
-
/**
|
|
1660
|
-
* Delete a session by its IdP session ID (sid).
|
|
1661
|
-
*
|
|
1662
|
-
* Used for both normal logout and backchannel logout flows.
|
|
1663
|
-
*
|
|
1664
|
-
* @param sid - The session.sid to delete
|
|
1665
|
-
*/
|
|
1666
|
-
delete(sid: string): Promise<void>;
|
|
1667
|
-
}
|
|
1668
|
-
/**
|
|
1669
|
-
* In-memory session store implementation using Maps.
|
|
1670
|
-
*
|
|
1671
|
-
* Suitable for:
|
|
1672
|
-
* - Development and testing
|
|
1673
|
-
* - Single-server deployments
|
|
1674
|
-
* - Applications without high availability requirements
|
|
1675
|
-
*
|
|
1676
|
-
* NOT suitable for:
|
|
1677
|
-
* - Multi-server deployments (sessions not shared)
|
|
1678
|
-
* - High availability scenarios (sessions lost on restart)
|
|
1679
|
-
* - Production applications with distributed architecture
|
|
1680
|
-
*
|
|
1681
|
-
* For production, implement SessionStore with Redis or a database.
|
|
1682
|
-
*
|
|
1683
|
-
* @template TExtended - Type-safe custom data that consumers can add to sessions
|
|
1684
|
-
*/
|
|
1685
|
-
declare class InMemorySessionStore<TExtended = {}> implements SessionStore<TExtended> {
|
|
1686
|
-
private sessions;
|
|
1687
|
-
create(session: Session<TExtended>): Promise<void>;
|
|
1688
|
-
get(sid: string): Promise<Session<TExtended> | null>;
|
|
1689
|
-
update(sid: string, data: Partial<Session<TExtended>>): Promise<void>;
|
|
1690
|
-
delete(sid: string): Promise<void>;
|
|
1691
|
-
}
|
|
1692
1930
|
type SSOConfig<
|
|
1693
1931
|
TSessionData = {},
|
|
1694
1932
|
TUserData = {}
|
|
@@ -1750,11 +1988,12 @@ type SSO<
|
|
|
1750
1988
|
TUserData = {}
|
|
1751
1989
|
> = {
|
|
1752
1990
|
config: SSOConfig<TSessionData, TUserData>;
|
|
1753
|
-
getUser: (request: Request) => Promise<
|
|
1754
|
-
getRequiredUser: (request: Request) => Promise<
|
|
1991
|
+
getUser: (request: Request) => Promise<User | undefined>;
|
|
1992
|
+
getRequiredUser: (request: Request) => Promise<User>;
|
|
1755
1993
|
getJwt: (request: Request) => Promise<string | undefined>;
|
|
1756
1994
|
initiateLogin: (config: LoginConfig, requestUrl?: string) => Promise<Response>;
|
|
1757
1995
|
logout: (request: Request, config?: LoginConfig) => Promise<Response>;
|
|
1996
|
+
logoutBackChannel: (request: Request) => Promise<Response>;
|
|
1758
1997
|
callbackHandler: (request: Request) => Promise<Response>;
|
|
1759
1998
|
handler: (request: Request) => Promise<Response>;
|
|
1760
1999
|
};
|
|
@@ -1852,7 +2091,7 @@ type TenantValidators = {
|
|
|
1852
2091
|
/**
|
|
1853
2092
|
* Configuration for tenant management
|
|
1854
2093
|
*/
|
|
1855
|
-
type TenantConfig =
|
|
2094
|
+
type TenantConfig = Record<string, never>;
|
|
1856
2095
|
/**
|
|
1857
2096
|
* Tenant service interface
|
|
1858
2097
|
*/
|
|
@@ -1950,7 +2189,7 @@ type StoredTenant<TExtended = {}> = {
|
|
|
1950
2189
|
* Serialized Enterprise Standard configuration.
|
|
1951
2190
|
* This is a JSON-serializable version of the ESConfig with non-serializable items excluded.
|
|
1952
2191
|
*/
|
|
1953
|
-
config?:
|
|
2192
|
+
config?: unknown;
|
|
1954
2193
|
} & TExtended;
|
|
1955
2194
|
/**
|
|
1956
2195
|
* Abstract interface for tenant storage backends.
|
|
@@ -2068,12 +2307,15 @@ type DevConfig = {
|
|
|
2068
2307
|
type VaultConfig = LfvConfig | AzureConfig | AwsConfig | GcpConfig | OpenBaoConfig | DevConfig;
|
|
2069
2308
|
declare function vault(config?: VaultConfig): Vault;
|
|
2070
2309
|
/**
|
|
2071
|
-
* Helper gets the user from the Request using the supplied EnterpriseStandard or the default instance
|
|
2310
|
+
* Helper gets the user from the Request using the supplied EnterpriseStandard or the default instance.
|
|
2311
|
+
* Checks SSO first, then CIAM if SSO returns undefined.
|
|
2072
2312
|
*/
|
|
2073
|
-
declare function getUser2(request: Request, es?: EnterpriseStandard): Promise<
|
|
2074
|
-
declare function getRequiredUser2(request: Request, es?: EnterpriseStandard): Promise<
|
|
2313
|
+
declare function getUser2(request: Request, es?: EnterpriseStandard): Promise<User | undefined>;
|
|
2314
|
+
declare function getRequiredUser2(request: Request, es?: EnterpriseStandard): Promise<User>;
|
|
2075
2315
|
declare function initiateLogin2(config: LoginConfig, es?: EnterpriseStandard): Promise<Response>;
|
|
2076
2316
|
declare function callback(request: Request, es?: EnterpriseStandard): Promise<Response>;
|
|
2317
|
+
declare function logout(request: Request, es?: EnterpriseStandard): Promise<Response>;
|
|
2318
|
+
declare function logoutBackChannel2(request: Request, es?: EnterpriseStandard): Promise<Response>;
|
|
2077
2319
|
import { StandardSchemaV1 as StandardSchemaV18 } from "@standard-schema/spec";
|
|
2078
2320
|
/**
|
|
2079
2321
|
* Parse and validate a tenant creation request.
|
|
@@ -2264,7 +2506,7 @@ declare function getDefaultInstance(): EnterpriseStandard | undefined;
|
|
|
2264
2506
|
* @param message - The message to include in the response.
|
|
2265
2507
|
* @returns A 400 Response with the issues if it does, otherwise null.
|
|
2266
2508
|
*/
|
|
2267
|
-
declare function validationFailureResponse(issues:
|
|
2509
|
+
declare function validationFailureResponse(issues: unknown, message: string): Response;
|
|
2268
2510
|
/**
|
|
2269
2511
|
* Serializes an ESConfig or EnterpriseStandard instance to a JSON-serializable format
|
|
2270
2512
|
* by removing non-serializable properties like stores, validators, and functions.
|
|
@@ -2275,7 +2517,7 @@ declare function validationFailureResponse(issues: any, message: string): Respon
|
|
|
2275
2517
|
* @param configOrES - The ESConfig object or EnterpriseStandard instance to serialize
|
|
2276
2518
|
* @returns A JSON-serializable version of the config
|
|
2277
2519
|
*/
|
|
2278
|
-
declare function serializeESConfig(configOrES:
|
|
2520
|
+
declare function serializeESConfig(configOrES: unknown): unknown;
|
|
2279
2521
|
/**
|
|
2280
2522
|
* Get the workload identity from an incoming request.
|
|
2281
2523
|
* Returns undefined if no valid workload token is present.
|
|
@@ -2406,9 +2648,10 @@ type EnterpriseStandard = {
|
|
|
2406
2648
|
iam?: IAM;
|
|
2407
2649
|
workload?: Workload;
|
|
2408
2650
|
tenants?: Tenant;
|
|
2651
|
+
ciam?: CIAM;
|
|
2409
2652
|
/**
|
|
2410
2653
|
* Framework-agnostic request handler that routes requests to the appropriate
|
|
2411
|
-
* standard handler (SSO, IAM, or
|
|
2654
|
+
* standard handler (SSO, IAM, Workload, or CIAM) based on the configured URLs.
|
|
2412
2655
|
*/
|
|
2413
2656
|
handler: (request: Request) => Promise<Response>;
|
|
2414
2657
|
};
|
|
@@ -2419,6 +2662,7 @@ type ESConfig = {
|
|
|
2419
2662
|
iam?: IAMConfig;
|
|
2420
2663
|
workload?: WorkloadConfig;
|
|
2421
2664
|
tenant?: TenantConfig;
|
|
2665
|
+
ciam?: CIAMConfig;
|
|
2422
2666
|
validators?: ESValidators;
|
|
2423
2667
|
};
|
|
2424
2668
|
type ESValidators = {
|
|
@@ -2428,4 +2672,4 @@ type ESValidators = {
|
|
|
2428
2672
|
tenant: TenantValidators;
|
|
2429
2673
|
};
|
|
2430
2674
|
declare function enterpriseStandard(appId: string, initConfig?: ESConfig): Promise<EnterpriseStandard>;
|
|
2431
|
-
export { workloadTokenResponseSchema, workloadHandler, workload, vault, validationFailureResponse, validateWorkloadToken, userSchema, tokenResponseSchema, tenant as tenantManagement, sso, serializeESConfig, sendTenantWebhook2 as sendTenantWebhook, revokeWorkloadToken, parseTenantRequest2 as parseTenantRequest, oidcCallbackSchema, jwtAssertionClaimsSchema, initiateLogin2 as initiateLogin, idTokenClaimsSchema, iam, groupResourceSchema, getWorkloadToken, getWorkload, getUser2 as getUser, getRequiredUser2 as getRequiredUser, getDefaultInstance, enterpriseStandard, callback, X509Certificate, WorkloadValidators, WorkloadTokenStore, WorkloadTokenResponse, WorkloadIdentity, WorkloadConfig, Workload, Vault, UsersInboundHandlerConfig, UserStore,
|
|
2675
|
+
export { workloadTokenResponseSchema, workloadHandler, workload, vault, validationFailureResponse, validateWorkloadToken, userSchema, tokenResponseSchema, tenant as tenantManagement, sso, serializeESConfig, sendTenantWebhook2 as sendTenantWebhook, revokeWorkloadToken, parseTenantRequest2 as parseTenantRequest, oidcCallbackSchema, logoutBackChannel2 as logoutBackChannel, logout, jwtAssertionClaimsSchema, initiateLogin2 as initiateLogin, idTokenClaimsSchema, iam, groupResourceSchema, getWorkloadToken, getWorkload, getUser2 as getUser, getRequiredUser2 as getRequiredUser, getDefaultInstance, enterpriseStandard, ciam, callback, X509Certificate, WorkloadValidators, WorkloadTokenStore, WorkloadTokenResponse, WorkloadIdentity, WorkloadConfig, Workload, Vault, UsersInboundHandlerConfig, UserStore, User, TokenValidationResult, TokenResponse, TenantWebhookPayload, TenantValidators, TenantStore, TenantStatus, TenantRequestError, TenantConfig, Tenant, StoredUser, StoredTenant, StoredGroup, SessionStore, ServerOnlyWorkloadConfig, User2 as ScimUser, ScimResult, ScimListResponse, ScimError, SSOValidators, SSOHandlerConfig, SSOConfig, SSO, Role, PhoneNumber, OidcCallbackParams, Name, MagicLinkStore, MagicLink, JwtBearerWorkloadConfig, JWTAssertionClaims, InMemoryWorkloadTokenStore, InMemoryUserStore, InMemoryTenantStore, InMemorySessionStore, InMemoryMagicLinkStore, InMemoryGroupStore, IdTokenClaims, IAMValidators, IAMUsersInbound, IAMHandlerConfig, IAMGroupsOutbound, IAMGroupsInbound, IAMConfig, IAM, GroupsInboundHandlerConfig, GroupStore, GroupResource, GroupMember, Group, EnvironmentType, EnterpriseUser, EnterpriseStandard, EnterpriseExtension, Email, ESValidators, CreateUserOptions, CreateTenantResponse, CreateTenantRequest, CreateGroupOptions, ClientCredentialsWorkloadConfig, CachedWorkloadToken, CIAMConfig, CIAM, BaseUser, Address };
|