@stackwright-pro/auth 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +33 -0
- package/dist/index.d.mts +1009 -0
- package/dist/index.d.ts +1009 -0
- package/dist/index.js +1182 -0
- package/dist/index.js.map +1 -0
- package/dist/index.mjs +1124 -0
- package/dist/index.mjs.map +1 -0
- package/package.json +46 -0
package/dist/index.d.mts
ADDED
|
@@ -0,0 +1,1009 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
import { X509Certificate } from '@peculiar/x509';
|
|
3
|
+
import * as React from 'react';
|
|
4
|
+
import React__default, { ReactNode, ReactElement } from 'react';
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* Core Type Definitions for Stackwright Auth
|
|
8
|
+
*
|
|
9
|
+
* These types define the foundational contract for authentication.
|
|
10
|
+
* All auth functionality builds on these interfaces.
|
|
11
|
+
*/
|
|
12
|
+
/**
|
|
13
|
+
* Authenticated user representation
|
|
14
|
+
* Normalized across PKI and OIDC providers
|
|
15
|
+
*/
|
|
16
|
+
interface AuthUser {
|
|
17
|
+
id: string;
|
|
18
|
+
email?: string;
|
|
19
|
+
name?: string;
|
|
20
|
+
roles: string[];
|
|
21
|
+
permissions?: string[];
|
|
22
|
+
metadata?: Record<string, any>;
|
|
23
|
+
}
|
|
24
|
+
/**
|
|
25
|
+
* Session representation
|
|
26
|
+
* Contains user info and expiration details
|
|
27
|
+
*/
|
|
28
|
+
interface AuthSession {
|
|
29
|
+
user: AuthUser;
|
|
30
|
+
expiresAt: number;
|
|
31
|
+
issuedAt: number;
|
|
32
|
+
refreshToken?: string;
|
|
33
|
+
}
|
|
34
|
+
/**
|
|
35
|
+
* PKI-specific configuration
|
|
36
|
+
* Supports DoD CAC, PIV cards, and custom PKI deployments
|
|
37
|
+
*/
|
|
38
|
+
interface PKIConfig {
|
|
39
|
+
type: 'pki';
|
|
40
|
+
profile: 'dod_cac' | 'piv' | 'custom';
|
|
41
|
+
source: 'gateway_headers' | 'direct_tls';
|
|
42
|
+
headerPrefix?: string;
|
|
43
|
+
verifiedHeader?: string;
|
|
44
|
+
requiredValue?: string;
|
|
45
|
+
caChain?: string;
|
|
46
|
+
requiredOU?: string[];
|
|
47
|
+
allowedIssuers?: string[];
|
|
48
|
+
}
|
|
49
|
+
/**
|
|
50
|
+
* OIDC configuration
|
|
51
|
+
* Supports major providers + custom OIDC implementations
|
|
52
|
+
*/
|
|
53
|
+
interface OIDCConfig {
|
|
54
|
+
type: 'oidc';
|
|
55
|
+
provider: 'cognito' | 'azure_ad' | 'authentik' | 'keycloak' | 'okta' | 'auth0' | 'custom';
|
|
56
|
+
discoveryUrl: string;
|
|
57
|
+
clientId: string;
|
|
58
|
+
clientSecret: string;
|
|
59
|
+
redirectUri?: string;
|
|
60
|
+
claimsMapping?: {
|
|
61
|
+
user_id?: string;
|
|
62
|
+
email?: string;
|
|
63
|
+
name?: string;
|
|
64
|
+
roles?: string;
|
|
65
|
+
};
|
|
66
|
+
quirks?: {
|
|
67
|
+
skipIssuerCheck?: boolean;
|
|
68
|
+
useRefreshTokenRotation?: boolean;
|
|
69
|
+
};
|
|
70
|
+
}
|
|
71
|
+
/**
|
|
72
|
+
* Union of all auth configurations
|
|
73
|
+
* Discriminated by 'type' field for type safety
|
|
74
|
+
*/
|
|
75
|
+
type AuthConfig = PKIConfig | OIDCConfig;
|
|
76
|
+
/**
|
|
77
|
+
* Component-level auth configuration (from YAML)
|
|
78
|
+
* Defines access requirements for individual components
|
|
79
|
+
*/
|
|
80
|
+
interface ComponentAuthConfig {
|
|
81
|
+
required_roles?: string[];
|
|
82
|
+
required_permissions?: string[];
|
|
83
|
+
fallback?: 'hide' | 'placeholder' | 'message';
|
|
84
|
+
fallback_message?: string;
|
|
85
|
+
}
|
|
86
|
+
/**
|
|
87
|
+
* Role-based access control configuration
|
|
88
|
+
* Defines roles, permissions, and route protection
|
|
89
|
+
*/
|
|
90
|
+
interface RBACConfig {
|
|
91
|
+
roles: Array<{
|
|
92
|
+
name: string;
|
|
93
|
+
permissions?: string[];
|
|
94
|
+
}>;
|
|
95
|
+
protected_routes?: Array<{
|
|
96
|
+
path: string;
|
|
97
|
+
roles: string[];
|
|
98
|
+
}>;
|
|
99
|
+
public_routes?: string[];
|
|
100
|
+
}
|
|
101
|
+
/**
|
|
102
|
+
* Auth context passed to providers during authentication
|
|
103
|
+
*/
|
|
104
|
+
interface AuthContext$1 {
|
|
105
|
+
headers?: Record<string, string>;
|
|
106
|
+
query?: Record<string, string>;
|
|
107
|
+
cookies?: Record<string, string>;
|
|
108
|
+
}
|
|
109
|
+
/**
|
|
110
|
+
* Provider interface that both PKI and OIDC implementations must satisfy
|
|
111
|
+
* Ensures consistent behavior across auth strategies
|
|
112
|
+
*/
|
|
113
|
+
interface AuthProvider$1 {
|
|
114
|
+
authenticate(context: AuthContext$1): Promise<AuthUser | null>;
|
|
115
|
+
validate(session: AuthSession): Promise<boolean>;
|
|
116
|
+
refresh?(session: AuthSession): Promise<AuthSession | null>;
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
/**
|
|
120
|
+
* Zod Schemas for Runtime Validation
|
|
121
|
+
*
|
|
122
|
+
* These schemas provide runtime validation for all auth-related data structures.
|
|
123
|
+
* They mirror the TypeScript types but enforce validation at runtime.
|
|
124
|
+
*/
|
|
125
|
+
|
|
126
|
+
/**
|
|
127
|
+
* PKI Configuration Schema
|
|
128
|
+
* Validates PKI auth config with sensible defaults
|
|
129
|
+
*/
|
|
130
|
+
declare const pkiConfigSchema: z.ZodObject<{
|
|
131
|
+
type: z.ZodLiteral<"pki">;
|
|
132
|
+
profile: z.ZodEnum<{
|
|
133
|
+
dod_cac: "dod_cac";
|
|
134
|
+
piv: "piv";
|
|
135
|
+
custom: "custom";
|
|
136
|
+
}>;
|
|
137
|
+
source: z.ZodEnum<{
|
|
138
|
+
gateway_headers: "gateway_headers";
|
|
139
|
+
direct_tls: "direct_tls";
|
|
140
|
+
}>;
|
|
141
|
+
headerPrefix: z.ZodDefault<z.ZodOptional<z.ZodString>>;
|
|
142
|
+
verifiedHeader: z.ZodDefault<z.ZodOptional<z.ZodString>>;
|
|
143
|
+
requiredValue: z.ZodDefault<z.ZodOptional<z.ZodString>>;
|
|
144
|
+
caChain: z.ZodOptional<z.ZodString>;
|
|
145
|
+
requiredOU: z.ZodOptional<z.ZodArray<z.ZodString>>;
|
|
146
|
+
allowedIssuers: z.ZodOptional<z.ZodArray<z.ZodString>>;
|
|
147
|
+
}, z.core.$strip>;
|
|
148
|
+
/**
|
|
149
|
+
* OIDC Configuration Schema
|
|
150
|
+
* Validates OIDC provider config including claims mapping and quirks
|
|
151
|
+
*/
|
|
152
|
+
declare const oidcConfigSchema: z.ZodObject<{
|
|
153
|
+
type: z.ZodLiteral<"oidc">;
|
|
154
|
+
provider: z.ZodEnum<{
|
|
155
|
+
custom: "custom";
|
|
156
|
+
cognito: "cognito";
|
|
157
|
+
azure_ad: "azure_ad";
|
|
158
|
+
authentik: "authentik";
|
|
159
|
+
keycloak: "keycloak";
|
|
160
|
+
okta: "okta";
|
|
161
|
+
auth0: "auth0";
|
|
162
|
+
}>;
|
|
163
|
+
discoveryUrl: z.ZodString;
|
|
164
|
+
clientId: z.ZodString;
|
|
165
|
+
clientSecret: z.ZodString;
|
|
166
|
+
redirectUri: z.ZodOptional<z.ZodString>;
|
|
167
|
+
claimsMapping: z.ZodOptional<z.ZodObject<{
|
|
168
|
+
user_id: z.ZodOptional<z.ZodString>;
|
|
169
|
+
email: z.ZodOptional<z.ZodString>;
|
|
170
|
+
name: z.ZodOptional<z.ZodString>;
|
|
171
|
+
roles: z.ZodOptional<z.ZodString>;
|
|
172
|
+
}, z.core.$strip>>;
|
|
173
|
+
quirks: z.ZodOptional<z.ZodObject<{
|
|
174
|
+
skipIssuerCheck: z.ZodOptional<z.ZodBoolean>;
|
|
175
|
+
useRefreshTokenRotation: z.ZodOptional<z.ZodBoolean>;
|
|
176
|
+
}, z.core.$strip>>;
|
|
177
|
+
}, z.core.$strip>;
|
|
178
|
+
/**
|
|
179
|
+
* Discriminated Union Schema
|
|
180
|
+
* Auto-discriminates based on 'type' field for type-safe validation
|
|
181
|
+
*/
|
|
182
|
+
declare const authConfigSchema: z.ZodDiscriminatedUnion<[z.ZodObject<{
|
|
183
|
+
type: z.ZodLiteral<"pki">;
|
|
184
|
+
profile: z.ZodEnum<{
|
|
185
|
+
dod_cac: "dod_cac";
|
|
186
|
+
piv: "piv";
|
|
187
|
+
custom: "custom";
|
|
188
|
+
}>;
|
|
189
|
+
source: z.ZodEnum<{
|
|
190
|
+
gateway_headers: "gateway_headers";
|
|
191
|
+
direct_tls: "direct_tls";
|
|
192
|
+
}>;
|
|
193
|
+
headerPrefix: z.ZodDefault<z.ZodOptional<z.ZodString>>;
|
|
194
|
+
verifiedHeader: z.ZodDefault<z.ZodOptional<z.ZodString>>;
|
|
195
|
+
requiredValue: z.ZodDefault<z.ZodOptional<z.ZodString>>;
|
|
196
|
+
caChain: z.ZodOptional<z.ZodString>;
|
|
197
|
+
requiredOU: z.ZodOptional<z.ZodArray<z.ZodString>>;
|
|
198
|
+
allowedIssuers: z.ZodOptional<z.ZodArray<z.ZodString>>;
|
|
199
|
+
}, z.core.$strip>, z.ZodObject<{
|
|
200
|
+
type: z.ZodLiteral<"oidc">;
|
|
201
|
+
provider: z.ZodEnum<{
|
|
202
|
+
custom: "custom";
|
|
203
|
+
cognito: "cognito";
|
|
204
|
+
azure_ad: "azure_ad";
|
|
205
|
+
authentik: "authentik";
|
|
206
|
+
keycloak: "keycloak";
|
|
207
|
+
okta: "okta";
|
|
208
|
+
auth0: "auth0";
|
|
209
|
+
}>;
|
|
210
|
+
discoveryUrl: z.ZodString;
|
|
211
|
+
clientId: z.ZodString;
|
|
212
|
+
clientSecret: z.ZodString;
|
|
213
|
+
redirectUri: z.ZodOptional<z.ZodString>;
|
|
214
|
+
claimsMapping: z.ZodOptional<z.ZodObject<{
|
|
215
|
+
user_id: z.ZodOptional<z.ZodString>;
|
|
216
|
+
email: z.ZodOptional<z.ZodString>;
|
|
217
|
+
name: z.ZodOptional<z.ZodString>;
|
|
218
|
+
roles: z.ZodOptional<z.ZodString>;
|
|
219
|
+
}, z.core.$strip>>;
|
|
220
|
+
quirks: z.ZodOptional<z.ZodObject<{
|
|
221
|
+
skipIssuerCheck: z.ZodOptional<z.ZodBoolean>;
|
|
222
|
+
useRefreshTokenRotation: z.ZodOptional<z.ZodBoolean>;
|
|
223
|
+
}, z.core.$strip>>;
|
|
224
|
+
}, z.core.$strip>], "type">;
|
|
225
|
+
/**
|
|
226
|
+
* Component Auth Configuration Schema
|
|
227
|
+
* Validates YAML-based component auth requirements
|
|
228
|
+
*/
|
|
229
|
+
declare const componentAuthSchema: z.ZodOptional<z.ZodObject<{
|
|
230
|
+
required_roles: z.ZodOptional<z.ZodArray<z.ZodString>>;
|
|
231
|
+
required_permissions: z.ZodOptional<z.ZodArray<z.ZodString>>;
|
|
232
|
+
fallback: z.ZodDefault<z.ZodOptional<z.ZodEnum<{
|
|
233
|
+
hide: "hide";
|
|
234
|
+
placeholder: "placeholder";
|
|
235
|
+
message: "message";
|
|
236
|
+
}>>>;
|
|
237
|
+
fallback_message: z.ZodOptional<z.ZodString>;
|
|
238
|
+
}, z.core.$strip>>;
|
|
239
|
+
/**
|
|
240
|
+
* RBAC Configuration Schema
|
|
241
|
+
* Validates role definitions, permissions, and route protection rules
|
|
242
|
+
*/
|
|
243
|
+
declare const rbacConfigSchema: z.ZodObject<{
|
|
244
|
+
roles: z.ZodArray<z.ZodObject<{
|
|
245
|
+
name: z.ZodString;
|
|
246
|
+
permissions: z.ZodOptional<z.ZodArray<z.ZodString>>;
|
|
247
|
+
}, z.core.$strip>>;
|
|
248
|
+
protected_routes: z.ZodOptional<z.ZodArray<z.ZodObject<{
|
|
249
|
+
path: z.ZodString;
|
|
250
|
+
roles: z.ZodArray<z.ZodString>;
|
|
251
|
+
}, z.core.$strip>>>;
|
|
252
|
+
public_routes: z.ZodOptional<z.ZodArray<z.ZodString>>;
|
|
253
|
+
}, z.core.$strip>;
|
|
254
|
+
/**
|
|
255
|
+
* Auth User Schema
|
|
256
|
+
* Validates user objects with required id and roles
|
|
257
|
+
*/
|
|
258
|
+
declare const authUserSchema: z.ZodObject<{
|
|
259
|
+
id: z.ZodString;
|
|
260
|
+
email: z.ZodOptional<z.ZodString>;
|
|
261
|
+
name: z.ZodOptional<z.ZodString>;
|
|
262
|
+
roles: z.ZodArray<z.ZodString>;
|
|
263
|
+
permissions: z.ZodOptional<z.ZodArray<z.ZodString>>;
|
|
264
|
+
metadata: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodAny>>;
|
|
265
|
+
}, z.core.$strip>;
|
|
266
|
+
/**
|
|
267
|
+
* Auth Session Schema
|
|
268
|
+
* Validates session structure including expiration timestamps
|
|
269
|
+
*/
|
|
270
|
+
declare const authSessionSchema: z.ZodObject<{
|
|
271
|
+
user: z.ZodObject<{
|
|
272
|
+
id: z.ZodString;
|
|
273
|
+
email: z.ZodOptional<z.ZodString>;
|
|
274
|
+
name: z.ZodOptional<z.ZodString>;
|
|
275
|
+
roles: z.ZodArray<z.ZodString>;
|
|
276
|
+
permissions: z.ZodOptional<z.ZodArray<z.ZodString>>;
|
|
277
|
+
metadata: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodAny>>;
|
|
278
|
+
}, z.core.$strip>;
|
|
279
|
+
expiresAt: z.ZodNumber;
|
|
280
|
+
issuedAt: z.ZodNumber;
|
|
281
|
+
refreshToken: z.ZodOptional<z.ZodString>;
|
|
282
|
+
}, z.core.$strip>;
|
|
283
|
+
|
|
284
|
+
/**
|
|
285
|
+
* PKI Authentication Provider
|
|
286
|
+
*
|
|
287
|
+
* Implements certificate-based authentication supporting:
|
|
288
|
+
* - Gateway header extraction (e.g., from NGINX, HAProxy)
|
|
289
|
+
* - Direct TLS termination
|
|
290
|
+
* - DoD CAC profile validation
|
|
291
|
+
* - Custom PKI deployments
|
|
292
|
+
*/
|
|
293
|
+
|
|
294
|
+
declare class PKIProvider implements AuthProvider$1 {
|
|
295
|
+
private config;
|
|
296
|
+
constructor(config: PKIConfig);
|
|
297
|
+
authenticate(context: AuthContext$1): Promise<AuthUser | null>;
|
|
298
|
+
validate(session: AuthSession): Promise<boolean>;
|
|
299
|
+
/**
|
|
300
|
+
* Extract roles from certificate based on organizational units
|
|
301
|
+
* Can be customized per deployment via subclassing
|
|
302
|
+
*/
|
|
303
|
+
private extractRolesFromCertificate;
|
|
304
|
+
}
|
|
305
|
+
|
|
306
|
+
/**
|
|
307
|
+
* OIDC Authentication Provider
|
|
308
|
+
*
|
|
309
|
+
* Implements the AuthProvider interface for OAuth2/OIDC authentication.
|
|
310
|
+
* Supports major providers (Cognito, Azure AD, Keycloak, etc.) with
|
|
311
|
+
* configurable claims mapping and provider-specific quirks handling.
|
|
312
|
+
*/
|
|
313
|
+
|
|
314
|
+
/**
|
|
315
|
+
* OIDC Provider
|
|
316
|
+
*
|
|
317
|
+
* Handles OAuth2/OIDC authentication flows including:
|
|
318
|
+
* - Discovery of OIDC configuration
|
|
319
|
+
* - Authorization code exchange
|
|
320
|
+
* - JWT validation
|
|
321
|
+
* - Session refresh
|
|
322
|
+
* - Provider-specific quirks (Keycloak, Cognito, etc.)
|
|
323
|
+
*/
|
|
324
|
+
declare class OIDCProvider implements AuthProvider$1 {
|
|
325
|
+
private config;
|
|
326
|
+
private metadata;
|
|
327
|
+
constructor(config: OIDCConfig);
|
|
328
|
+
/**
|
|
329
|
+
* Initialize provider by discovering OIDC configuration
|
|
330
|
+
*
|
|
331
|
+
* Call this during app startup to pre-fetch OIDC metadata.
|
|
332
|
+
* If not called, metadata will be lazily loaded on first use.
|
|
333
|
+
*/
|
|
334
|
+
initialize(): Promise<void>;
|
|
335
|
+
/**
|
|
336
|
+
* Get metadata (lazy load if not initialized)
|
|
337
|
+
*
|
|
338
|
+
* @returns OIDC metadata
|
|
339
|
+
*/
|
|
340
|
+
private getMetadata;
|
|
341
|
+
/**
|
|
342
|
+
* Authenticate user by exchanging authorization code for tokens
|
|
343
|
+
*
|
|
344
|
+
* This is called after the user is redirected back from the OIDC provider
|
|
345
|
+
* with an authorization code in the query parameters.
|
|
346
|
+
*
|
|
347
|
+
* @param context - Auth context with query params containing authorization code
|
|
348
|
+
* @returns Authenticated user or null if no code present
|
|
349
|
+
* @throws Error if token exchange or validation fails
|
|
350
|
+
*/
|
|
351
|
+
authenticate(context: AuthContext$1): Promise<AuthUser | null>;
|
|
352
|
+
/**
|
|
353
|
+
* Validate session (check if token is still valid)
|
|
354
|
+
*
|
|
355
|
+
* Simple time-based validation. For more security, you could:
|
|
356
|
+
* - Call the userinfo endpoint
|
|
357
|
+
* - Verify token hasn't been revoked
|
|
358
|
+
* - Check against a session store
|
|
359
|
+
*
|
|
360
|
+
* @param session - Session to validate
|
|
361
|
+
* @returns true if session is still valid
|
|
362
|
+
*/
|
|
363
|
+
validate(session: AuthSession): Promise<boolean>;
|
|
364
|
+
/**
|
|
365
|
+
* Refresh session using refresh token
|
|
366
|
+
*
|
|
367
|
+
* When the access token expires, use the refresh token to get new tokens
|
|
368
|
+
* without requiring the user to re-authenticate.
|
|
369
|
+
*
|
|
370
|
+
* @param session - Session with refresh token
|
|
371
|
+
* @returns Updated session with new tokens, or null if refresh failed
|
|
372
|
+
*/
|
|
373
|
+
refresh(session: AuthSession): Promise<AuthSession | null>;
|
|
374
|
+
/**
|
|
375
|
+
* Get authorization URL for initiating OIDC login
|
|
376
|
+
*
|
|
377
|
+
* Redirect users to this URL to start the authentication flow.
|
|
378
|
+
*
|
|
379
|
+
* @param redirectUri - Where to redirect after authentication
|
|
380
|
+
* @param state - CSRF protection token (recommended)
|
|
381
|
+
* @returns Authorization URL
|
|
382
|
+
*/
|
|
383
|
+
getAuthorizationUrl(redirectUri: string, state?: string): Promise<string>;
|
|
384
|
+
/**
|
|
385
|
+
* Extract claim value with fallback
|
|
386
|
+
*
|
|
387
|
+
* Tries custom mapped key first, then falls back to default key.
|
|
388
|
+
*
|
|
389
|
+
* @param claims - JWT claims
|
|
390
|
+
* @param mappedKey - Custom mapped key from config
|
|
391
|
+
* @param defaultKey - Default OIDC key
|
|
392
|
+
* @returns Claim value or undefined
|
|
393
|
+
*/
|
|
394
|
+
private getClaimValue;
|
|
395
|
+
/**
|
|
396
|
+
* Extract roles from claims (provider-specific logic)
|
|
397
|
+
*
|
|
398
|
+
* Different OIDC providers store roles in different places:
|
|
399
|
+
* - Standard: 'roles' claim
|
|
400
|
+
* - Keycloak: realm_access.roles
|
|
401
|
+
* - Cognito: cognito:groups
|
|
402
|
+
* - Azure AD: roles claim
|
|
403
|
+
*
|
|
404
|
+
* @param claims - JWT claims
|
|
405
|
+
* @returns Array of role strings
|
|
406
|
+
*/
|
|
407
|
+
private extractRoles;
|
|
408
|
+
}
|
|
409
|
+
|
|
410
|
+
/**
|
|
411
|
+
* X.509 Certificate Parser
|
|
412
|
+
*
|
|
413
|
+
* Utilities for parsing and validating X.509 certificates.
|
|
414
|
+
* Supports both PEM/DER formats and gateway header extraction.
|
|
415
|
+
*/
|
|
416
|
+
|
|
417
|
+
interface ParsedCertificate {
|
|
418
|
+
subject: {
|
|
419
|
+
commonName?: string;
|
|
420
|
+
email?: string;
|
|
421
|
+
organizationalUnit?: string[];
|
|
422
|
+
organization?: string;
|
|
423
|
+
country?: string;
|
|
424
|
+
};
|
|
425
|
+
issuer: {
|
|
426
|
+
commonName?: string;
|
|
427
|
+
organization?: string;
|
|
428
|
+
};
|
|
429
|
+
serialNumber: string;
|
|
430
|
+
notBefore: Date;
|
|
431
|
+
notAfter: Date;
|
|
432
|
+
isValid: boolean;
|
|
433
|
+
}
|
|
434
|
+
/**
|
|
435
|
+
* Parse X.509 certificate from PEM string or DER buffer
|
|
436
|
+
*/
|
|
437
|
+
declare function parseCertificate(pemOrDer: string | ArrayBuffer): ParsedCertificate;
|
|
438
|
+
/**
|
|
439
|
+
* Extract EDIPI from DoD CAC certificate
|
|
440
|
+
* EDIPI is stored in OID 2.16.840.1.101.2.1.11.42
|
|
441
|
+
*/
|
|
442
|
+
declare function extractEDIPI(cert: X509Certificate): string | undefined;
|
|
443
|
+
/**
|
|
444
|
+
* Validate certificate against DoD CAC requirements
|
|
445
|
+
*/
|
|
446
|
+
declare function validateDoDCAC(parsed: ParsedCertificate): boolean;
|
|
447
|
+
/**
|
|
448
|
+
* Parse certificate from gateway headers (x-client-cert-* pattern)
|
|
449
|
+
*/
|
|
450
|
+
declare function parseCertFromHeaders(headers: Record<string, string>, prefix?: string): ParsedCertificate | null;
|
|
451
|
+
|
|
452
|
+
/**
|
|
453
|
+
* OIDC Discovery Client
|
|
454
|
+
*
|
|
455
|
+
* Handles OIDC provider discovery and authorization URL generation.
|
|
456
|
+
* Follows the OpenID Connect Discovery 1.0 specification.
|
|
457
|
+
*/
|
|
458
|
+
/**
|
|
459
|
+
* OIDC Provider Metadata (from .well-known/openid-configuration)
|
|
460
|
+
*/
|
|
461
|
+
interface OIDCMetadata {
|
|
462
|
+
issuer: string;
|
|
463
|
+
authorization_endpoint: string;
|
|
464
|
+
token_endpoint: string;
|
|
465
|
+
jwks_uri: string;
|
|
466
|
+
userinfo_endpoint?: string;
|
|
467
|
+
end_session_endpoint?: string;
|
|
468
|
+
scopes_supported?: string[];
|
|
469
|
+
response_types_supported?: string[];
|
|
470
|
+
}
|
|
471
|
+
/**
|
|
472
|
+
* Discover OIDC provider configuration
|
|
473
|
+
*
|
|
474
|
+
* Fetches the OIDC discovery document from the well-known endpoint.
|
|
475
|
+
* This is the first step in any OIDC flow.
|
|
476
|
+
*
|
|
477
|
+
* @param discoveryUrl - Full URL to .well-known/openid-configuration
|
|
478
|
+
* @returns OIDC metadata with endpoints and capabilities
|
|
479
|
+
* @throws Error if discovery fails or metadata is invalid
|
|
480
|
+
*/
|
|
481
|
+
declare function discoverOIDC(discoveryUrl: string): Promise<OIDCMetadata>;
|
|
482
|
+
/**
|
|
483
|
+
* Generate authorization URL for OIDC login
|
|
484
|
+
*
|
|
485
|
+
* Builds the URL to redirect users to for authentication.
|
|
486
|
+
* Follows OAuth 2.0 authorization code flow.
|
|
487
|
+
*
|
|
488
|
+
* @param metadata - OIDC provider metadata from discovery
|
|
489
|
+
* @param clientId - OAuth client ID
|
|
490
|
+
* @param redirectUri - Where to redirect after authentication
|
|
491
|
+
* @param state - CSRF protection token (recommended)
|
|
492
|
+
* @param scopes - OAuth scopes to request
|
|
493
|
+
* @returns Authorization URL to redirect user to
|
|
494
|
+
*/
|
|
495
|
+
declare function buildAuthorizationUrl(metadata: OIDCMetadata, clientId: string, redirectUri: string, state?: string, scopes?: string[]): string;
|
|
496
|
+
|
|
497
|
+
/**
|
|
498
|
+
* OIDC Token Exchange & Validation
|
|
499
|
+
*
|
|
500
|
+
* Handles OAuth2 token exchange, refresh, and JWT validation.
|
|
501
|
+
* Uses jose for secure JWT operations.
|
|
502
|
+
*/
|
|
503
|
+
|
|
504
|
+
interface TokenSet {
|
|
505
|
+
access_token: string;
|
|
506
|
+
id_token: string;
|
|
507
|
+
refresh_token?: string;
|
|
508
|
+
expires_in: number;
|
|
509
|
+
token_type: string;
|
|
510
|
+
}
|
|
511
|
+
/**
|
|
512
|
+
* Exchange authorization code for tokens
|
|
513
|
+
*
|
|
514
|
+
* This is step 2 of the OAuth2 authorization code flow.
|
|
515
|
+
* The authorization code is exchanged for access/ID/refresh tokens.
|
|
516
|
+
*
|
|
517
|
+
* @param metadata - OIDC provider metadata
|
|
518
|
+
* @param code - Authorization code from callback
|
|
519
|
+
* @param clientId - OAuth client ID
|
|
520
|
+
* @param clientSecret - OAuth client secret
|
|
521
|
+
* @param redirectUri - Must match the redirect_uri used in authorization
|
|
522
|
+
* @returns Token set with access_token, id_token, and optionally refresh_token
|
|
523
|
+
* @throws Error if token exchange fails
|
|
524
|
+
*/
|
|
525
|
+
declare function exchangeCodeForTokens(metadata: OIDCMetadata, code: string, clientId: string, clientSecret: string, redirectUri: string): Promise<TokenSet>;
|
|
526
|
+
/**
|
|
527
|
+
* Refresh access token using refresh token
|
|
528
|
+
*
|
|
529
|
+
* When access tokens expire, use the refresh token to get new ones
|
|
530
|
+
* without requiring user to re-authenticate.
|
|
531
|
+
*
|
|
532
|
+
* @param metadata - OIDC provider metadata
|
|
533
|
+
* @param refreshToken - Refresh token from initial token exchange
|
|
534
|
+
* @param clientId - OAuth client ID
|
|
535
|
+
* @param clientSecret - OAuth client secret
|
|
536
|
+
* @returns New token set
|
|
537
|
+
* @throws Error if refresh fails
|
|
538
|
+
*/
|
|
539
|
+
declare function refreshAccessToken(metadata: OIDCMetadata, refreshToken: string, clientId: string, clientSecret: string): Promise<TokenSet>;
|
|
540
|
+
/**
|
|
541
|
+
* Validate ID token JWT and extract claims
|
|
542
|
+
*
|
|
543
|
+
* Verifies the JWT signature using the provider's JWKS and validates
|
|
544
|
+
* standard claims (issuer, audience, expiration).
|
|
545
|
+
*
|
|
546
|
+
* This is critical for security - never trust an ID token without validation!
|
|
547
|
+
*
|
|
548
|
+
* @param idToken - JWT ID token from token exchange
|
|
549
|
+
* @param jwksUri - JWKS URI from OIDC metadata
|
|
550
|
+
* @param issuer - Expected issuer (should match token's iss claim)
|
|
551
|
+
* @param clientId - Expected audience (should match token's aud claim)
|
|
552
|
+
* @param skipIssuerCheck - Skip issuer validation (use for Keycloak quirks)
|
|
553
|
+
* @returns Validated JWT payload with user claims
|
|
554
|
+
* @throws Error if JWT validation fails
|
|
555
|
+
*/
|
|
556
|
+
declare function validateIdToken(idToken: string, jwksUri: string, issuer: string, clientId: string, skipIssuerCheck?: boolean): Promise<Record<string, any>>;
|
|
557
|
+
|
|
558
|
+
/**
|
|
559
|
+
* Keycloak-specific OIDC Adapter
|
|
560
|
+
*
|
|
561
|
+
* Keycloak has several quirks in its OIDC implementation that require
|
|
562
|
+
* special handling. This adapter normalizes Keycloak behavior.
|
|
563
|
+
*
|
|
564
|
+
* Known Issues:
|
|
565
|
+
* 1. Issuer in token doesn't always match discovery URL
|
|
566
|
+
* 2. Refresh token rotation is inconsistent
|
|
567
|
+
* 3. Claims structure differs from standard OIDC
|
|
568
|
+
* 4. Role mapping is non-standard (realm_access.roles)
|
|
569
|
+
*/
|
|
570
|
+
/**
|
|
571
|
+
* Keycloak-specific OIDC adapter
|
|
572
|
+
*
|
|
573
|
+
* Use this when working with Keycloak to handle its many quirks.
|
|
574
|
+
* Tested with Keycloak 19.x - 23.x
|
|
575
|
+
*/
|
|
576
|
+
declare class KeycloakAdapter {
|
|
577
|
+
/**
|
|
578
|
+
* Normalize Keycloak issuer (remove /auth prefix if present)
|
|
579
|
+
*
|
|
580
|
+
* Keycloak's issuer URLs changed between versions:
|
|
581
|
+
* - Pre-17: https://keycloak.example.com/auth/realms/myrealm
|
|
582
|
+
* - Post-17: https://keycloak.example.com/realms/myrealm
|
|
583
|
+
*
|
|
584
|
+
* This normalizes to the post-17 format.
|
|
585
|
+
*
|
|
586
|
+
* @param issuer - Issuer from token or metadata
|
|
587
|
+
* @returns Normalized issuer
|
|
588
|
+
*/
|
|
589
|
+
static normalizeIssuer(issuer: string): string;
|
|
590
|
+
/**
|
|
591
|
+
* Map Keycloak-specific claims to standard format
|
|
592
|
+
*
|
|
593
|
+
* Keycloak stores roles and groups in non-standard locations:
|
|
594
|
+
* - Roles: realm_access.roles (not standard)
|
|
595
|
+
* - Groups: groups array (sometimes, if configured)
|
|
596
|
+
* - Username: preferred_username (not always 'name')
|
|
597
|
+
*
|
|
598
|
+
* @param tokenPayload - Raw JWT payload from Keycloak
|
|
599
|
+
* @returns Normalized claims matching AuthUser interface
|
|
600
|
+
*/
|
|
601
|
+
static mapClaims(tokenPayload: Record<string, any>): Record<string, any>;
|
|
602
|
+
/**
|
|
603
|
+
* Keycloak refresh tokens should be refreshed earlier than spec suggests
|
|
604
|
+
*
|
|
605
|
+
* Keycloak's refresh token rotation is buggy and sometimes fails if you
|
|
606
|
+
* wait too long. Refresh aggressively when less than 10 minutes remain.
|
|
607
|
+
*
|
|
608
|
+
* @param expiresIn - Seconds until token expires
|
|
609
|
+
* @returns true if token should be refreshed now
|
|
610
|
+
*/
|
|
611
|
+
static shouldRefreshToken(expiresIn: number): boolean;
|
|
612
|
+
}
|
|
613
|
+
|
|
614
|
+
interface SessionManagerConfig {
|
|
615
|
+
/**
|
|
616
|
+
* Secret key for JWT signing (must be at least 32 bytes)
|
|
617
|
+
*/
|
|
618
|
+
secret: string;
|
|
619
|
+
/**
|
|
620
|
+
* Session duration in seconds (default: 15 minutes)
|
|
621
|
+
*/
|
|
622
|
+
sessionDuration?: number;
|
|
623
|
+
/**
|
|
624
|
+
* Algorithm for JWT signing (default: HS256)
|
|
625
|
+
*/
|
|
626
|
+
algorithm?: string;
|
|
627
|
+
/**
|
|
628
|
+
* Issuer claim for JWT
|
|
629
|
+
*/
|
|
630
|
+
issuer?: string;
|
|
631
|
+
/**
|
|
632
|
+
* Audience claim for JWT
|
|
633
|
+
*/
|
|
634
|
+
audience?: string;
|
|
635
|
+
}
|
|
636
|
+
declare class SessionManager {
|
|
637
|
+
private secret;
|
|
638
|
+
private sessionDuration;
|
|
639
|
+
private algorithm;
|
|
640
|
+
private issuer?;
|
|
641
|
+
private audience?;
|
|
642
|
+
constructor(config: SessionManagerConfig);
|
|
643
|
+
/**
|
|
644
|
+
* Create a new session for authenticated user
|
|
645
|
+
*/
|
|
646
|
+
createSession(user: AuthUser, refreshToken?: string): Promise<AuthSession>;
|
|
647
|
+
/**
|
|
648
|
+
* Sign session into a JWT
|
|
649
|
+
*/
|
|
650
|
+
signSession(session: AuthSession): Promise<string>;
|
|
651
|
+
/**
|
|
652
|
+
* Verify and decode session JWT
|
|
653
|
+
*/
|
|
654
|
+
verifySession(jwt: string): Promise<AuthSession | null>;
|
|
655
|
+
/**
|
|
656
|
+
* Check if session is expired
|
|
657
|
+
*/
|
|
658
|
+
isExpired(session: AuthSession): boolean;
|
|
659
|
+
/**
|
|
660
|
+
* Check if session should be refreshed (within 5 minutes of expiry)
|
|
661
|
+
*/
|
|
662
|
+
shouldRefresh(session: AuthSession): boolean;
|
|
663
|
+
/**
|
|
664
|
+
* Refresh session (extend expiration)
|
|
665
|
+
*/
|
|
666
|
+
refreshSession(session: AuthSession): Promise<AuthSession>;
|
|
667
|
+
/**
|
|
668
|
+
* Serialize session to string (for cookies/localStorage)
|
|
669
|
+
*/
|
|
670
|
+
serialize(session: AuthSession): Promise<string>;
|
|
671
|
+
/**
|
|
672
|
+
* Deserialize session from string
|
|
673
|
+
*/
|
|
674
|
+
deserialize(serialized: string): Promise<AuthSession | null>;
|
|
675
|
+
}
|
|
676
|
+
|
|
677
|
+
/**
|
|
678
|
+
* Cookie options for session cookies
|
|
679
|
+
*/
|
|
680
|
+
interface CookieOptions {
|
|
681
|
+
/**
|
|
682
|
+
* Cookie name (default: 'stackwright_session')
|
|
683
|
+
*/
|
|
684
|
+
name?: string;
|
|
685
|
+
/**
|
|
686
|
+
* Domain for cookie
|
|
687
|
+
*/
|
|
688
|
+
domain?: string;
|
|
689
|
+
/**
|
|
690
|
+
* Path for cookie (default: '/')
|
|
691
|
+
*/
|
|
692
|
+
path?: string;
|
|
693
|
+
/**
|
|
694
|
+
* Max age in seconds
|
|
695
|
+
*/
|
|
696
|
+
maxAge?: number;
|
|
697
|
+
/**
|
|
698
|
+
* HttpOnly flag (default: true)
|
|
699
|
+
*/
|
|
700
|
+
httpOnly?: boolean;
|
|
701
|
+
/**
|
|
702
|
+
* Secure flag (default: true in production)
|
|
703
|
+
*/
|
|
704
|
+
secure?: boolean;
|
|
705
|
+
/**
|
|
706
|
+
* SameSite policy (default: 'lax')
|
|
707
|
+
*/
|
|
708
|
+
sameSite?: 'strict' | 'lax' | 'none';
|
|
709
|
+
}
|
|
710
|
+
/**
|
|
711
|
+
* Serialize cookie with options
|
|
712
|
+
*/
|
|
713
|
+
declare function serializeCookie(name: string, value: string, options?: CookieOptions): string;
|
|
714
|
+
/**
|
|
715
|
+
* Parse cookie string into key-value pairs
|
|
716
|
+
*/
|
|
717
|
+
declare function parseCookies(cookieHeader?: string): Record<string, string>;
|
|
718
|
+
/**
|
|
719
|
+
* Create a cookie header for clearing/deleting a cookie
|
|
720
|
+
*/
|
|
721
|
+
declare function clearCookie(name: string, options?: Pick<CookieOptions, 'domain' | 'path'>): string;
|
|
722
|
+
|
|
723
|
+
/**
|
|
724
|
+
* RBAC Engine for checking roles and permissions
|
|
725
|
+
*/
|
|
726
|
+
declare class RBACEngine {
|
|
727
|
+
private config;
|
|
728
|
+
private rolePermissions;
|
|
729
|
+
constructor(config: RBACConfig);
|
|
730
|
+
/**
|
|
731
|
+
* Build internal map of role → permissions for fast lookups
|
|
732
|
+
*/
|
|
733
|
+
private buildRolePermissionMap;
|
|
734
|
+
/**
|
|
735
|
+
* Check if user has a specific role
|
|
736
|
+
*/
|
|
737
|
+
hasRole(user: AuthUser, role: string): boolean;
|
|
738
|
+
/**
|
|
739
|
+
* Check if user has any of the specified roles
|
|
740
|
+
*/
|
|
741
|
+
hasAnyRole(user: AuthUser, roles: string[]): boolean;
|
|
742
|
+
/**
|
|
743
|
+
* Check if user has all of the specified roles
|
|
744
|
+
*/
|
|
745
|
+
hasAllRoles(user: AuthUser, roles: string[]): boolean;
|
|
746
|
+
/**
|
|
747
|
+
* Check if user has a specific permission
|
|
748
|
+
* Permissions are checked both:
|
|
749
|
+
* 1. Directly in user.permissions array
|
|
750
|
+
* 2. Through role-based permissions from config
|
|
751
|
+
*/
|
|
752
|
+
hasPermission(user: AuthUser, permission: string): boolean;
|
|
753
|
+
/**
|
|
754
|
+
* Check if user has any of the specified permissions
|
|
755
|
+
*/
|
|
756
|
+
hasAnyPermission(user: AuthUser, permissions: string[]): boolean;
|
|
757
|
+
/**
|
|
758
|
+
* Check if user has all of the specified permissions
|
|
759
|
+
*/
|
|
760
|
+
hasAllPermissions(user: AuthUser, permissions: string[]): boolean;
|
|
761
|
+
/**
|
|
762
|
+
* Check if route is public (no auth required)
|
|
763
|
+
*/
|
|
764
|
+
isPublicRoute(path: string): boolean;
|
|
765
|
+
/**
|
|
766
|
+
* Check if user can access a route based on protected_routes config
|
|
767
|
+
*/
|
|
768
|
+
canAccessRoute(user: AuthUser | null, path: string): boolean;
|
|
769
|
+
/**
|
|
770
|
+
* Check if user can access a component based on component auth config
|
|
771
|
+
*/
|
|
772
|
+
canAccessComponent(user: AuthUser | null, authConfig: ComponentAuthConfig | undefined): boolean;
|
|
773
|
+
private matchPath;
|
|
774
|
+
}
|
|
775
|
+
|
|
776
|
+
/**
|
|
777
|
+
* Auth context value provided to component tree
|
|
778
|
+
*/
|
|
779
|
+
interface AuthContextValue {
|
|
780
|
+
/**
|
|
781
|
+
* Currently authenticated user (null if not authenticated)
|
|
782
|
+
*/
|
|
783
|
+
user: AuthUser | null;
|
|
784
|
+
/**
|
|
785
|
+
* Current session (null if not authenticated)
|
|
786
|
+
*/
|
|
787
|
+
session: AuthSession | null;
|
|
788
|
+
/**
|
|
789
|
+
* Whether user is authenticated
|
|
790
|
+
*/
|
|
791
|
+
isAuthenticated: boolean;
|
|
792
|
+
/**
|
|
793
|
+
* Whether auth is still loading
|
|
794
|
+
*/
|
|
795
|
+
isLoading: boolean;
|
|
796
|
+
/**
|
|
797
|
+
* Check if user has a specific role
|
|
798
|
+
*/
|
|
799
|
+
hasRole: (role: string) => boolean;
|
|
800
|
+
/**
|
|
801
|
+
* Check if user has a specific permission
|
|
802
|
+
*/
|
|
803
|
+
hasPermission: (permission: string) => boolean;
|
|
804
|
+
/**
|
|
805
|
+
* Check if user has any of the specified roles
|
|
806
|
+
*/
|
|
807
|
+
hasAnyRole: (roles: string[]) => boolean;
|
|
808
|
+
/**
|
|
809
|
+
* Check if user has all of the specified permissions
|
|
810
|
+
*/
|
|
811
|
+
hasAllPermissions: (permissions: string[]) => boolean;
|
|
812
|
+
}
|
|
813
|
+
/**
|
|
814
|
+
* Auth context - provides authentication state to components
|
|
815
|
+
*/
|
|
816
|
+
declare const AuthContext: React.Context<AuthContextValue | null>;
|
|
817
|
+
/**
|
|
818
|
+
* Hook to access auth context
|
|
819
|
+
* Throws error if used outside AuthProvider
|
|
820
|
+
*/
|
|
821
|
+
declare function useAuth(): AuthContextValue;
|
|
822
|
+
/**
|
|
823
|
+
* Hook to require authentication
|
|
824
|
+
* Returns null and logs warning if not authenticated
|
|
825
|
+
*/
|
|
826
|
+
declare function useRequireAuth(): AuthContextValue | null;
|
|
827
|
+
|
|
828
|
+
interface AuthProviderProps {
|
|
829
|
+
/**
|
|
830
|
+
* Current authenticated user (null if not authenticated)
|
|
831
|
+
*/
|
|
832
|
+
user: AuthUser | null;
|
|
833
|
+
/**
|
|
834
|
+
* Current session (null if not authenticated)
|
|
835
|
+
*/
|
|
836
|
+
session: AuthSession | null;
|
|
837
|
+
/**
|
|
838
|
+
* RBAC configuration for role/permission checking
|
|
839
|
+
*/
|
|
840
|
+
rbacConfig: RBACConfig;
|
|
841
|
+
/**
|
|
842
|
+
* Whether auth is still loading
|
|
843
|
+
*/
|
|
844
|
+
isLoading?: boolean;
|
|
845
|
+
/**
|
|
846
|
+
* Child components
|
|
847
|
+
*/
|
|
848
|
+
children: ReactNode;
|
|
849
|
+
}
|
|
850
|
+
/**
|
|
851
|
+
* AuthProvider - Provides authentication state to component tree
|
|
852
|
+
*
|
|
853
|
+
* @example
|
|
854
|
+
* ```tsx
|
|
855
|
+
* <AuthProvider user={user} session={session} rbacConfig={config}>
|
|
856
|
+
* <App />
|
|
857
|
+
* </AuthProvider>
|
|
858
|
+
* ```
|
|
859
|
+
*/
|
|
860
|
+
declare function AuthProvider({ user, session, rbacConfig, isLoading, children, }: AuthProviderProps): ReactElement;
|
|
861
|
+
|
|
862
|
+
/**
|
|
863
|
+
* DoD CAC Profile Configuration
|
|
864
|
+
*
|
|
865
|
+
* Pre-built profile for DoD Common Access Card (CAC) certificates.
|
|
866
|
+
*
|
|
867
|
+
* This profile includes:
|
|
868
|
+
* - List of trusted DoD CA issuers
|
|
869
|
+
* - Required OU validation (DOD)
|
|
870
|
+
* - EDIPI extraction for user ID
|
|
871
|
+
*
|
|
872
|
+
* Last updated: 2025-01 (DoD PKI CA list)
|
|
873
|
+
*
|
|
874
|
+
* Note: DoD PKI infrastructure is regularly updated. Verify current CA list at:
|
|
875
|
+
* https://public.cyber.mil/pki-pke/
|
|
876
|
+
*/
|
|
877
|
+
|
|
878
|
+
/**
|
|
879
|
+
* DoD CAC profile configuration
|
|
880
|
+
*
|
|
881
|
+
* This provides sensible defaults for DoD CAC authentication in most deployments.
|
|
882
|
+
* Assumes gateway (e.g., NGINX, HAProxy) handles mTLS and forwards headers.
|
|
883
|
+
*/
|
|
884
|
+
declare const DOD_CAC_PROFILE: Omit<PKIConfig, 'type'>;
|
|
885
|
+
/**
|
|
886
|
+
* Create DoD CAC configuration with custom overrides
|
|
887
|
+
*
|
|
888
|
+
* @example
|
|
889
|
+
* ```typescript
|
|
890
|
+
* const config = createDoDCACConfig({
|
|
891
|
+
* source: 'direct_tls', // If terminating TLS in Node.js
|
|
892
|
+
* headerPrefix: 'ssl-client-', // Custom gateway header prefix
|
|
893
|
+
* });
|
|
894
|
+
* ```
|
|
895
|
+
*/
|
|
896
|
+
declare function createDoDCACConfig(overrides?: Partial<PKIConfig>): PKIConfig;
|
|
897
|
+
/**
|
|
898
|
+
* Minimal DoD CAC config for development/testing
|
|
899
|
+
* Relaxes some requirements for local testing without real CAC cards
|
|
900
|
+
*/
|
|
901
|
+
declare function createDoDCACDevConfig(): PKIConfig;
|
|
902
|
+
|
|
903
|
+
/**
|
|
904
|
+
* Props that any component wrapped with withAuth will receive
|
|
905
|
+
*/
|
|
906
|
+
interface ComponentProps {
|
|
907
|
+
id?: string;
|
|
908
|
+
[key: string]: any;
|
|
909
|
+
}
|
|
910
|
+
/**
|
|
911
|
+
* Higher-order component that wraps a component with authentication checks
|
|
912
|
+
*
|
|
913
|
+
* @example
|
|
914
|
+
* ```tsx
|
|
915
|
+
* const ProtectedButton = withAuth(Button, {
|
|
916
|
+
* required_roles: ['ADMIN'],
|
|
917
|
+
* fallback: 'message',
|
|
918
|
+
* fallback_message: 'Only admins can see this button'
|
|
919
|
+
* });
|
|
920
|
+
* ```
|
|
921
|
+
*
|
|
922
|
+
* @param Component - The component to wrap
|
|
923
|
+
* @param authConfig - Authentication requirements from YAML
|
|
924
|
+
* @returns Wrapped component with auth enforcement
|
|
925
|
+
*/
|
|
926
|
+
declare function withAuth<P extends ComponentProps>(Component: React__default.ComponentType<P>, authConfig?: ComponentAuthConfig): React__default.ComponentType<P>;
|
|
927
|
+
/**
|
|
928
|
+
* Custom fallback component (for advanced use cases)
|
|
929
|
+
*/
|
|
930
|
+
declare function withAuthFallback<P extends ComponentProps>(Component: React__default.ComponentType<P>, authConfig: ComponentAuthConfig, FallbackComponent: React__default.ComponentType<any>): React__default.ComponentType<P>;
|
|
931
|
+
|
|
932
|
+
/**
|
|
933
|
+
* Register the auth decorator for use by content renderers
|
|
934
|
+
*
|
|
935
|
+
* This should be called once in your app's initialization (e.g., _app.tsx)
|
|
936
|
+
* to enable auth-aware component rendering.
|
|
937
|
+
*
|
|
938
|
+
* @example
|
|
939
|
+
* ```tsx
|
|
940
|
+
* // In pages/_app.tsx
|
|
941
|
+
* import { registerAuthDecorator } from '@stackwright-pro/auth';
|
|
942
|
+
*
|
|
943
|
+
* registerAuthDecorator();
|
|
944
|
+
*
|
|
945
|
+
* function MyApp({ Component, pageProps }: AppProps) {
|
|
946
|
+
* return (
|
|
947
|
+
* <AuthProvider {...authProps}>
|
|
948
|
+
* <Component {...pageProps} />
|
|
949
|
+
* </AuthProvider>
|
|
950
|
+
* );
|
|
951
|
+
* }
|
|
952
|
+
* ```
|
|
953
|
+
*/
|
|
954
|
+
declare function registerAuthDecorator(): void;
|
|
955
|
+
/**
|
|
956
|
+
* Get the registered auth decorator (for use by content renderers)
|
|
957
|
+
*
|
|
958
|
+
* Returns null if auth is not registered, allowing graceful degradation.
|
|
959
|
+
* This is the function that OSS core would call to check if auth is available.
|
|
960
|
+
*
|
|
961
|
+
* @returns The withAuth decorator function, or null if not registered
|
|
962
|
+
*/
|
|
963
|
+
declare function getAuthDecorator(): typeof withAuth | null;
|
|
964
|
+
/**
|
|
965
|
+
* Wrap a component with auth if decorator is registered and config exists
|
|
966
|
+
*
|
|
967
|
+
* This is a safe wrapper that OSS packages can use without depending on auth.
|
|
968
|
+
* If auth is not registered, returns the original component unchanged.
|
|
969
|
+
* If auth config is missing/undefined, returns the original component unchanged.
|
|
970
|
+
*
|
|
971
|
+
* @example
|
|
972
|
+
* ```tsx
|
|
973
|
+
* // In content renderer (can live in OSS core!)\n * function renderContentItem(item: ContentItem) {
|
|
974
|
+
* const Component = getComponentFromRegistry(item.type);
|
|
975
|
+
*
|
|
976
|
+
* // Apply auth if available
|
|
977
|
+
* const WrappedComponent = maybeWrapWithAuth(Component, item.auth);
|
|
978
|
+
*
|
|
979
|
+
* return <WrappedComponent {...item} />;
|
|
980
|
+
* }
|
|
981
|
+
* ```
|
|
982
|
+
*
|
|
983
|
+
* @param Component - Component to wrap
|
|
984
|
+
* @param authConfig - Auth configuration from YAML (optional)
|
|
985
|
+
* @returns Wrapped component if auth is registered, original component otherwise
|
|
986
|
+
*/
|
|
987
|
+
declare function maybeWrapWithAuth<P extends {
|
|
988
|
+
id?: string;
|
|
989
|
+
[key: string]: any;
|
|
990
|
+
}>(Component: React__default.ComponentType<P>, authConfig?: ComponentAuthConfig): React__default.ComponentType<P>;
|
|
991
|
+
/**
|
|
992
|
+
* Type guard to check if content item has auth config
|
|
993
|
+
*
|
|
994
|
+
* Useful for conditionally applying auth in renderers without
|
|
995
|
+
* needing to import auth types.
|
|
996
|
+
*
|
|
997
|
+
* @example
|
|
998
|
+
* ```tsx
|
|
999
|
+
* if (hasAuthConfig(item)) {
|
|
1000
|
+
* // TypeScript knows item.auth exists
|
|
1001
|
+
* WrappedComponent = maybeWrapWithAuth(Component, item.auth);
|
|
1002
|
+
* }
|
|
1003
|
+
* ```
|
|
1004
|
+
*/
|
|
1005
|
+
declare function hasAuthConfig(item: any): item is {
|
|
1006
|
+
auth: ComponentAuthConfig;
|
|
1007
|
+
};
|
|
1008
|
+
|
|
1009
|
+
export { type AuthConfig, AuthContext, type AuthContextValue, AuthProvider, type AuthProviderProps, type AuthSession, type AuthUser, type ComponentAuthConfig, type ComponentProps, type CookieOptions, DOD_CAC_PROFILE, KeycloakAdapter, type OIDCConfig, type OIDCMetadata, OIDCProvider, type PKIConfig, PKIProvider, type ParsedCertificate, type RBACConfig, RBACEngine, SessionManager, type SessionManagerConfig, type TokenSet, authConfigSchema, authSessionSchema, authUserSchema, buildAuthorizationUrl, clearCookie, componentAuthSchema, createDoDCACConfig, createDoDCACDevConfig, discoverOIDC, exchangeCodeForTokens, extractEDIPI, getAuthDecorator, hasAuthConfig, maybeWrapWithAuth, oidcConfigSchema, parseCertFromHeaders, parseCertificate, parseCookies, pkiConfigSchema, rbacConfigSchema, refreshAccessToken, registerAuthDecorator, serializeCookie, useAuth, useRequireAuth, validateDoDCAC, validateIdToken, withAuth, withAuthFallback };
|