@serafort/core 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.
@@ -0,0 +1,331 @@
1
+ /**
2
+ * Configuration options for initializing the Serafort SDK client.
3
+ */
4
+ interface RetryConfig {
5
+ /** Maximum number of retry attempts. Default: 3 */
6
+ maxRetries?: number;
7
+ /** Initial retry delay in milliseconds. Default: 500ms */
8
+ initialDelayMs?: number;
9
+ /** Maximum retry delay in milliseconds. Default: 5000ms */
10
+ maxDelayMs?: number;
11
+ }
12
+ interface SerafortConfig {
13
+ /** Base URL of the Serafort IAM backend (e.g. "https://auth.acme.com" or "http://localhost:3333") */
14
+ endpoint?: string;
15
+ /** Alias for endpoint */
16
+ baseUrl?: string;
17
+ /** Client identifier for Machine-to-Machine (M2M) authentication */
18
+ clientId?: string;
19
+ /** Client secret for Machine-to-Machine (M2M) authentication */
20
+ clientSecret?: string;
21
+ /** Publishable key for client-side and B2B public operations (starts with pk_live_ or pk_test_) */
22
+ publishableKey?: string;
23
+ /** Domain identifier (e.g. "auth.acme.com") */
24
+ domain?: string;
25
+ /** Request timeout in milliseconds. Default: 10,000ms */
26
+ timeout?: number;
27
+ /** Custom retry policy configuration for network resilience */
28
+ retryPolicy?: RetryConfig;
29
+ /** Custom fetch function implementation (defaults to global fetch) */
30
+ fetch?: typeof fetch;
31
+ }
32
+ /**
33
+ * Resolved user security context decoded from a verified JWT token.
34
+ */
35
+ interface UserContext {
36
+ /** The unique user identifier */
37
+ userId: string;
38
+ /** The tenant or organization identifier */
39
+ tenantId: string;
40
+ /** The primary email address of the user, if available */
41
+ email?: string;
42
+ /** Assigned roles (e.g. ["admin", "billing_manager"]) */
43
+ roles: string[];
44
+ /** Granted granular permissions (e.g. ["org:read", "billing:write"]) */
45
+ permissions: string[];
46
+ /** Raw decoded JWT payload claims */
47
+ claims: Record<string, unknown>;
48
+ }
49
+ /**
50
+ * OAuth2 token response payload from /oauth/token.
51
+ */
52
+ interface OAuthTokenResponse {
53
+ access_token: string;
54
+ token_type: string;
55
+ expires_in: number;
56
+ scope?: string;
57
+ refresh_token?: string;
58
+ }
59
+ /**
60
+ * Standard JSON Web Key (JWK) structure according to RFC 7517.
61
+ */
62
+ interface JWK {
63
+ kty: string;
64
+ kid?: string;
65
+ use?: string;
66
+ alg?: string;
67
+ n?: string;
68
+ e?: string;
69
+ crv?: string;
70
+ x?: string;
71
+ y?: string;
72
+ [key: string]: unknown;
73
+ }
74
+ /**
75
+ * Standard JSON Web Key Set (JWKS) structure according to RFC 7517.
76
+ */
77
+ interface JWKS {
78
+ keys: JWK[];
79
+ }
80
+ /**
81
+ * Standard API error detail item.
82
+ */
83
+ interface ApiErrorDetail {
84
+ field?: string;
85
+ message: string;
86
+ rule?: string;
87
+ }
88
+ /**
89
+ * Standard Serafort API response error envelope.
90
+ */
91
+ interface ApiErrorEnvelope {
92
+ status: 'error';
93
+ error: {
94
+ code: string;
95
+ message: string;
96
+ status: number;
97
+ details?: ApiErrorDetail[];
98
+ };
99
+ }
100
+
101
+ declare class JwksClient {
102
+ private readonly jwksUrl;
103
+ private readonly fetchImpl;
104
+ private cachedKeys;
105
+ private lastFetchedAt;
106
+ private readonly cacheTtlMs;
107
+ constructor(config: SerafortConfig, cacheTtlMs?: number);
108
+ /**
109
+ * Retrieves the CryptoKey matching the key ID (kid) from cache, or fetches from the JWKS endpoint.
110
+ */
111
+ getVerificationKey(kid?: string, alg?: string): Promise<CryptoKey>;
112
+ /**
113
+ * Refreshes public keys from the JWKS endpoint and imports them as CryptoKeys.
114
+ */
115
+ refreshJwks(): Promise<void>;
116
+ /**
117
+ * Imports a raw JWK into a Web Crypto CryptoKey.
118
+ */
119
+ importJwk(key: JWK): Promise<CryptoKey>;
120
+ }
121
+
122
+ interface TokenValidationOptions {
123
+ /** Expected JWT issuer (iss) */
124
+ expectedIssuer?: string;
125
+ /** Expected JWT audience (aud) */
126
+ expectedAudience?: string;
127
+ /** Allowed clock tolerance in seconds (default: 60s) */
128
+ clockToleranceSeconds?: number;
129
+ /** If true, skips cryptographic signature verification (ONLY for offline dev/testing) */
130
+ skipSignatureCheck?: boolean;
131
+ }
132
+ declare class B2BModule {
133
+ readonly config: SerafortConfig;
134
+ private readonly jwksClient;
135
+ private readonly baseUrl;
136
+ constructor(config: SerafortConfig, jwksClient?: JwksClient);
137
+ /**
138
+ * Validates a JWT token locally: checks signature against cached JWKS, verifies expiration,
139
+ * issuer, and audience, and decodes claims into a strongly-typed UserContext.
140
+ */
141
+ validateToken(token: string, options?: TokenValidationOptions): Promise<UserContext>;
142
+ /**
143
+ * Checks if the user context contains a specific granular permission.
144
+ * Supports wildcard matching (e.g. "org:*" matches "org:read").
145
+ */
146
+ hasPermission(userContext: UserContext, requiredPermission: string): boolean;
147
+ /**
148
+ * Checks if the user context contains a specific role.
149
+ */
150
+ hasRole(userContext: UserContext, requiredRole: string): boolean;
151
+ /**
152
+ * Constructs the Enterprise SSO Login URL for a specific tenant/organization.
153
+ */
154
+ getLoginUrl(tenantId: string, redirectUri: string, options?: {
155
+ state?: string;
156
+ connection?: string;
157
+ }): string;
158
+ /**
159
+ * Maps un-enveloped JWT claims to standard UserContext.
160
+ */
161
+ private mapClaimsToUserContext;
162
+ }
163
+
164
+ interface CachedToken {
165
+ accessToken: string;
166
+ expiresAt: number;
167
+ scope?: string;
168
+ }
169
+ /**
170
+ * High-concurrency, Promise-safe in-memory cache for Machine-to-Machine (M2M) access tokens.
171
+ * Automatically refreshes before expiration and coalesces concurrent refresh requests
172
+ * to avoid thundering-herd problems against the IAM server.
173
+ */
174
+ declare class M2MTokenCache {
175
+ private cache;
176
+ private inFlightRequests;
177
+ /**
178
+ * Refresh window buffer in seconds (default: 300s = 5 minutes).
179
+ * A token expiring within this window will be refreshed proactively.
180
+ */
181
+ private readonly refreshBufferSeconds;
182
+ constructor(refreshBufferSeconds?: number);
183
+ /**
184
+ * Retrieves a cached token if valid, or invokes the refresher function.
185
+ * If a fetch is already in flight for the given cache key, coalesces into that existing promise.
186
+ */
187
+ getOrFetch(cacheKey: string, refresher: () => Promise<{
188
+ accessToken: string;
189
+ expiresIn: number;
190
+ scope?: string;
191
+ }>, force?: boolean): Promise<string>;
192
+ /**
193
+ * Invalidates cached token for a specific cache key or clears all.
194
+ */
195
+ invalidate(cacheKey?: string): void;
196
+ /**
197
+ * Returns current cached item metadata (for diagnostics and testing).
198
+ */
199
+ get(cacheKey: string): CachedToken | undefined;
200
+ }
201
+
202
+ declare class M2MModule {
203
+ private readonly config;
204
+ private readonly cache;
205
+ private readonly baseUrl;
206
+ private readonly fetchImpl;
207
+ constructor(config: SerafortConfig, cache?: M2MTokenCache);
208
+ /**
209
+ * Retrieves a valid M2M access token.
210
+ * Pulls from memory cache if valid and outside the refresh buffer.
211
+ * If nearing expiration or missing, transparently requests a new token.
212
+ */
213
+ getAccessToken(scopes?: string[]): Promise<string>;
214
+ /**
215
+ * Forces a refresh of the access token, bypassing the cache.
216
+ * Useful when an API endpoint returns 401 due to early revocation.
217
+ */
218
+ forceRefreshToken(scopes?: string[]): Promise<string>;
219
+ /**
220
+ * Clears the in-memory token cache.
221
+ */
222
+ clearCache(): void;
223
+ /**
224
+ * Performs the HTTP request to the OAuth2 token endpoint using Client Credentials grant.
225
+ */
226
+ private fetchTokenNetwork;
227
+ }
228
+
229
+ /**
230
+ * Unified Serafort SDK Client.
231
+ * Provides Machine Identity (M2M) token caching and B2B User Identity / RBAC capabilities.
232
+ */
233
+ declare class SerafortClient {
234
+ readonly config: SerafortConfig;
235
+ readonly m2m: M2MModule;
236
+ readonly b2b: B2BModule;
237
+ constructor(config: SerafortConfig);
238
+ /**
239
+ * Helper shortcut to retrieve an M2M access token.
240
+ */
241
+ getAccessToken(scopes?: string[]): Promise<string>;
242
+ /**
243
+ * Helper shortcut to validate a JWT token and decode its UserContext.
244
+ */
245
+ validateToken(token: string): Promise<UserContext>;
246
+ }
247
+
248
+ /**
249
+ * Base exception class for all Serafort SDK errors.
250
+ */
251
+ declare class SerafortError extends Error {
252
+ readonly code: string;
253
+ readonly status: number;
254
+ readonly details: ApiErrorDetail[];
255
+ constructor(message: string, code?: string, status?: number, details?: ApiErrorDetail[]);
256
+ }
257
+ /**
258
+ * Authentication failed (invalid credentials, expired session, invalid JWT signature).
259
+ */
260
+ declare class AuthenticationError extends SerafortError {
261
+ constructor(message?: string, code?: string, details?: ApiErrorDetail[]);
262
+ }
263
+ /**
264
+ * Multi-Factor Authentication required to complete access.
265
+ */
266
+ declare class MfaRequiredError extends SerafortError {
267
+ readonly challengeId?: string;
268
+ readonly supportedMethods?: string[];
269
+ constructor(message?: string, challengeId?: string, supportedMethods?: string[], details?: ApiErrorDetail[]);
270
+ }
271
+ /**
272
+ * Request payload failed validation checks.
273
+ */
274
+ declare class ValidationError extends SerafortError {
275
+ constructor(message?: string, details?: ApiErrorDetail[]);
276
+ }
277
+ /**
278
+ * Rate limit exceeded (HTTP 429).
279
+ */
280
+ declare class RateLimitError extends SerafortError {
281
+ readonly retryAfterSeconds?: number;
282
+ constructor(message?: string, retryAfterSeconds?: number, details?: ApiErrorDetail[]);
283
+ }
284
+ /**
285
+ * Requested resource or tenant does not exist.
286
+ */
287
+ declare class NotFoundError extends SerafortError {
288
+ constructor(message?: string, code?: string, details?: ApiErrorDetail[]);
289
+ }
290
+ /**
291
+ * Network failure, client-side timeout, or host unreachable.
292
+ */
293
+ declare class NetworkError extends SerafortError {
294
+ constructor(message?: string, cause?: unknown);
295
+ }
296
+
297
+ interface DecodedJwt<T = Record<string, unknown>> {
298
+ header: {
299
+ alg: string;
300
+ typ?: string;
301
+ kid?: string;
302
+ [key: string]: unknown;
303
+ };
304
+ payload: T;
305
+ signature: Uint8Array;
306
+ signingInput: Uint8Array;
307
+ }
308
+ /**
309
+ * Decodes a base64url-encoded string into raw Uint8Array bytes.
310
+ */
311
+ declare function base64UrlToBytes(str: string): Uint8Array;
312
+ /**
313
+ * Decodes a base64url-encoded string into a UTF-8 string.
314
+ */
315
+ declare function base64UrlDecode(str: string): string;
316
+ /**
317
+ * Parses and separates the JWT into header, payload, signature, and signing input.
318
+ */
319
+ declare function parseJwt<T = Record<string, unknown>>(token: string): DecodedJwt<T>;
320
+
321
+ interface ExecuteWithRetryOptions {
322
+ retryConfig?: RetryConfig;
323
+ signal?: AbortSignal;
324
+ }
325
+ /**
326
+ * Executes an async operation with exponential backoff and jitter on retryable errors
327
+ * (HTTP 429, 502, 503, 504, and transient network errors).
328
+ */
329
+ declare function executeWithRetry<T>(fn: () => Promise<T>, options?: ExecuteWithRetryOptions): Promise<T>;
330
+
331
+ export { type ApiErrorDetail, type ApiErrorEnvelope, AuthenticationError, B2BModule, type JWK, type JWKS, JwksClient, M2MModule, M2MTokenCache, MfaRequiredError, NetworkError, NotFoundError, type OAuthTokenResponse, RateLimitError, type RetryConfig, SerafortClient, type SerafortConfig, SerafortError, type TokenValidationOptions, type UserContext, ValidationError, base64UrlDecode, base64UrlToBytes, executeWithRetry, parseJwt };