@dloizides/auth-client 2.0.0 → 2.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/CHANGELOG.md +63 -0
- package/dist/{AuthClient-Dim7HPRz.d.ts → AuthClient-BGr8L03W.d.mts} +62 -35
- package/dist/{AuthClient-Dim7HPRz.d.mts → AuthClient-D95OMajD.d.ts} +62 -35
- package/dist/TokenResponse-CY1CaU2l.d.mts +59 -0
- package/dist/TokenResponse-CY1CaU2l.d.ts +59 -0
- package/dist/index.d.mts +6 -28
- package/dist/index.d.ts +6 -28
- package/dist/index.js +213 -19
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +207 -20
- package/dist/index.mjs.map +1 -1
- package/dist/oidc/index.d.mts +127 -0
- package/dist/oidc/index.d.ts +127 -0
- package/dist/oidc/index.js +192 -0
- package/dist/oidc/index.js.map +1 -0
- package/dist/oidc/index.mjs +184 -0
- package/dist/oidc/index.mjs.map +1 -0
- package/dist/react.d.mts +2 -1
- package/dist/react.d.ts +2 -1
- package/package.json +11 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,68 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 2.1.0 (2026-05-17)
|
|
4
|
+
|
|
5
|
+
Additive release. Lays the groundwork for the "shrink identity service"
|
|
6
|
+
migration by extracting the OIDC primitives that three apps (BaseClient,
|
|
7
|
+
`apps/erevna-web`, `apps/katalogos-web`) had each duplicated in their own
|
|
8
|
+
`useKeycloakExchange.ts` files. No breaking changes — v2.0 callers continue
|
|
9
|
+
to work unchanged.
|
|
10
|
+
|
|
11
|
+
### Added
|
|
12
|
+
|
|
13
|
+
#### New `/oidc` sub-path entry
|
|
14
|
+
|
|
15
|
+
- `@dloizides/auth-client/oidc` — Pure OIDC primitives (no React, no hooks).
|
|
16
|
+
Lets non-React consumers tree-shake the `AuthClient` class away entirely.
|
|
17
|
+
|
|
18
|
+
#### OIDC primitives (also re-exported from the main entry)
|
|
19
|
+
|
|
20
|
+
- `fetchDiscoveryDocument({ issuerUrl, http })` — Fetches
|
|
21
|
+
`{issuer}/.well-known/openid-configuration` and caches the result per
|
|
22
|
+
issuer URL for the lifetime of the process. Throws on non-2xx or invalid
|
|
23
|
+
metadata. Cache cleared with `clearDiscoveryCache()` (test-only).
|
|
24
|
+
- `generateCodeVerifier(length?)` — RFC 7636-compliant PKCE verifier
|
|
25
|
+
generator. Defaults to 64 chars; enforces the 43..128 band.
|
|
26
|
+
- `deriveCodeChallenge(verifier)` — `BASE64URL(SHA256(verifier))` via
|
|
27
|
+
`crypto.subtle` (browser + Node 16+). Matches the RFC 7636 Appendix B
|
|
28
|
+
test vector.
|
|
29
|
+
- `generatePkcePair(length?)` — Convenience: fresh verifier + matching S256
|
|
30
|
+
challenge in one call.
|
|
31
|
+
- `exchangeAuthorizationCode({ http, baseUrl, realm, clientId, code,
|
|
32
|
+
redirectUri, codeVerifier })` — POSTs `grant_type=authorization_code` to
|
|
33
|
+
the realm's token endpoint. Returns a normalised `TokenResponse`.
|
|
34
|
+
- `refreshAccessToken({ http, baseUrl, realm, clientId, refreshToken })` —
|
|
35
|
+
POSTs `grant_type=refresh_token`. Same return shape.
|
|
36
|
+
|
|
37
|
+
#### `AuthClient` v2.1 surface
|
|
38
|
+
|
|
39
|
+
- `useDirectKcAuth?: boolean` config flag. Default `false`. When `true`,
|
|
40
|
+
apps can route their PKCE flow through the shared `exchangeAuthorizationCode`
|
|
41
|
+
primitive instead of the proxied identity-api `/auth/login` flow. The
|
|
42
|
+
flag is read-only at runtime via `AuthClient.isDirectMode()` so apps can
|
|
43
|
+
render conditionally on whether they've opted in.
|
|
44
|
+
- `acceptDirectKcTokens(response)` — Persists a `TokenResponse` produced by
|
|
45
|
+
the direct-KC flow into the configured storage, marks the inactivity
|
|
46
|
+
tracker active, and fires `onTokenAcquired`. Use this from the app's
|
|
47
|
+
`useKeycloakExchange.ts` hook after `exchangeAuthorizationCode()` resolves.
|
|
48
|
+
- `acceptDirectKcRefresh(response)` — Same as above but fires
|
|
49
|
+
`onTokenRefreshed` instead. Use after `refreshAccessToken()` swaps.
|
|
50
|
+
- `onTokenAcquired?: (tokens) => void` collaborator — fires after any login
|
|
51
|
+
path (OTP, password, direct-KC) successfully persists a fresh token
|
|
52
|
+
bundle. For app-side analytics/logging only — NOT designed for BFF
|
|
53
|
+
integration (Phase 2 designs that fresh).
|
|
54
|
+
- `onTokenRefreshed?: (tokens) => void` collaborator — fires after any
|
|
55
|
+
refresh (interceptor or direct-KC) persists a fresh bundle.
|
|
56
|
+
|
|
57
|
+
### Notes
|
|
58
|
+
|
|
59
|
+
- The `useDirectKcAuth` flag is the dormant-path flip mechanism. After v2.1
|
|
60
|
+
ships, apps still default to the proxied path. Per-app cutover (flipping
|
|
61
|
+
the flag to `true`) happens in subsequent steps of the
|
|
62
|
+
shrink-identity-to-tenant-service migration.
|
|
63
|
+
- The proxied `/auth/login`, `/auth/refresh`, `/auth/refresh-cookie` methods
|
|
64
|
+
on `AuthApiClient` are unchanged — production apps still call them.
|
|
65
|
+
|
|
3
66
|
## 2.0.0 (2026-05-07)
|
|
4
67
|
|
|
5
68
|
Major release. Extends the realm-aware OIDC core into a single source of truth for every auth surface in the dloizides.com portfolio: web cookies, mobile secure storage, biometric gating, silent token refresh with single-flight, inactivity enforcement, password reset, and sessions management.
|
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
import { H as HttpClient, T as TokenResponse } from './TokenResponse-CY1CaU2l.mjs';
|
|
2
|
+
|
|
1
3
|
/**
|
|
2
4
|
* Tiny dependency-free event emitter for auth lifecycle events.
|
|
3
5
|
*
|
|
@@ -19,39 +21,6 @@ declare class AuthEventEmitter {
|
|
|
19
21
|
clear(): void;
|
|
20
22
|
}
|
|
21
23
|
|
|
22
|
-
/**
|
|
23
|
-
* Minimal HTTP transport the package depends on.
|
|
24
|
-
*
|
|
25
|
-
* `AuthClient` orchestrates token-related HTTP calls (login, refresh, logout,
|
|
26
|
-
* password reset) but doesn't import `fetch` directly — keeping the package
|
|
27
|
-
* runtime-agnostic. Consumers wire native fetch, axios, ky, or whatever their
|
|
28
|
-
* platform exposes.
|
|
29
|
-
*/
|
|
30
|
-
interface HttpRequest {
|
|
31
|
-
url: string;
|
|
32
|
-
method: 'GET' | 'POST' | 'DELETE';
|
|
33
|
-
headers?: Record<string, string>;
|
|
34
|
-
/** When set, body is sent as the request body; serialization is the caller's job. */
|
|
35
|
-
body?: string;
|
|
36
|
-
/** Browser fetch only — pass through `credentials: 'include'` for cookie auth. */
|
|
37
|
-
credentials?: 'include' | 'same-origin' | 'omit';
|
|
38
|
-
}
|
|
39
|
-
interface HttpResponse {
|
|
40
|
-
status: number;
|
|
41
|
-
ok: boolean;
|
|
42
|
-
/** Parsed body (already JSON-decoded). `undefined` for 204 / empty bodies. */
|
|
43
|
-
data?: unknown;
|
|
44
|
-
}
|
|
45
|
-
type HttpClient = (request: HttpRequest) => Promise<HttpResponse>;
|
|
46
|
-
/**
|
|
47
|
-
* Wrap the platform's native `fetch` into the package's `HttpClient` shape.
|
|
48
|
-
* Decoded JSON when `Content-Type` is JSON, otherwise leaves data undefined.
|
|
49
|
-
*
|
|
50
|
-
* Errors thrown by `fetch` (network / abort) are NOT swallowed — callers
|
|
51
|
-
* decide whether to treat them as session-ending.
|
|
52
|
-
*/
|
|
53
|
-
declare function createFetchHttpClient(fetchImpl: typeof fetch): HttpClient;
|
|
54
|
-
|
|
55
24
|
/**
|
|
56
25
|
* Backend session record returned by `GET /me/sessions`.
|
|
57
26
|
*
|
|
@@ -328,6 +297,34 @@ interface AuthClientCollaborators {
|
|
|
328
297
|
interceptor?: RefreshInterceptor;
|
|
329
298
|
inactivityTracker?: InactivityTracker;
|
|
330
299
|
events?: AuthEventEmitter;
|
|
300
|
+
/**
|
|
301
|
+
* Observability hook fired when a fresh token bundle has been acquired
|
|
302
|
+
* (any login path: OTP, password, or direct-KC PKCE). For app-side
|
|
303
|
+
* analytics/logging only — NOT for BFF integration (Phase 2 designs that
|
|
304
|
+
* fresh).
|
|
305
|
+
*/
|
|
306
|
+
onTokenAcquired?: (tokens: AuthTokens) => void;
|
|
307
|
+
/**
|
|
308
|
+
* Observability hook fired when an existing token bundle has been
|
|
309
|
+
* refreshed. For app-side analytics/logging only.
|
|
310
|
+
*/
|
|
311
|
+
onTokenRefreshed?: (tokens: AuthTokens) => void;
|
|
312
|
+
}
|
|
313
|
+
/**
|
|
314
|
+
* Direct-to-KC (PKCE) routing flag added in v2.1.0.
|
|
315
|
+
*
|
|
316
|
+
* When `true`, `AuthClient` consumers can route their PKCE auth code through
|
|
317
|
+
* the shared OIDC primitives (`exchangeAuthorizationCodeViaOidc`,
|
|
318
|
+
* `refreshTokensViaOidc`) instead of the proxied identity-api `/auth/login`
|
|
319
|
+
* + `/auth/refresh` flow.
|
|
320
|
+
*
|
|
321
|
+
* Default `false` — v2.0 behavior unchanged.
|
|
322
|
+
*
|
|
323
|
+
* The flag is read-only at runtime (`isDirectMode()`) so apps can render
|
|
324
|
+
* conditionally on whether they've opted in.
|
|
325
|
+
*/
|
|
326
|
+
interface DirectKcOptions {
|
|
327
|
+
useDirectKcAuth?: boolean;
|
|
331
328
|
}
|
|
332
329
|
interface LoginOptions {
|
|
333
330
|
/** When true, request `offline_access` scope so the IdP issues a long-lived refresh token. */
|
|
@@ -339,15 +336,45 @@ interface LogoutOptions {
|
|
|
339
336
|
}
|
|
340
337
|
declare class AuthClient {
|
|
341
338
|
private readonly config;
|
|
339
|
+
private readonly directKcAuth;
|
|
342
340
|
private readonly tokenStorage;
|
|
343
341
|
private readonly api;
|
|
344
342
|
private readonly interceptor;
|
|
345
343
|
private readonly inactivityTracker;
|
|
346
344
|
private readonly events;
|
|
345
|
+
private readonly onTokenAcquired;
|
|
346
|
+
private readonly onTokenRefreshed;
|
|
347
347
|
/**
|
|
348
348
|
* @throws Error when `baseUrl`, `realm`, or `clientId` is missing or empty.
|
|
349
349
|
*/
|
|
350
|
-
constructor(config: AuthClientConfig, storage: TokenStorage, collaborators?: AuthClientCollaborators);
|
|
350
|
+
constructor(config: AuthClientConfig & DirectKcOptions, storage: TokenStorage, collaborators?: AuthClientCollaborators);
|
|
351
|
+
/**
|
|
352
|
+
* Whether this client is configured to route auth flows directly to
|
|
353
|
+
* Keycloak (v2.1.0 direct-KC path) instead of through the proxied
|
|
354
|
+
* identity-api `/auth/*` endpoints.
|
|
355
|
+
*
|
|
356
|
+
* Apps can render conditionally on this — e.g. to swap a login form for
|
|
357
|
+
* a "Sign in with Keycloak" redirect button.
|
|
358
|
+
*/
|
|
359
|
+
isDirectMode(): boolean;
|
|
360
|
+
/**
|
|
361
|
+
* Persist a token bundle produced by an external flow (e.g. the
|
|
362
|
+
* app-side `useKeycloakExchange` hook that consumes the shared
|
|
363
|
+
* `exchangeAuthorizationCode` primitive). Fires `onTokenAcquired` after
|
|
364
|
+
* persistence and marks the inactivity tracker active.
|
|
365
|
+
*
|
|
366
|
+
* Designed for the v2.1.0 direct-KC path where the PKCE code exchange
|
|
367
|
+
* happens in the app's React-Query hook (which needs `useDispatch`/etc.)
|
|
368
|
+
* but the token persistence + observability should still flow through
|
|
369
|
+
* the shared client.
|
|
370
|
+
*/
|
|
371
|
+
acceptDirectKcTokens(response: TokenResponse): Promise<AuthTokens>;
|
|
372
|
+
/**
|
|
373
|
+
* Same as {@link acceptDirectKcTokens} but fires `onTokenRefreshed`.
|
|
374
|
+
* Use after a `refreshAccessToken()` swap to keep observability counts
|
|
375
|
+
* separated between "fresh login" and "silent refresh".
|
|
376
|
+
*/
|
|
377
|
+
acceptDirectKcRefresh(response: TokenResponse): Promise<AuthTokens>;
|
|
351
378
|
/**
|
|
352
379
|
* Build an {@link AuthClient} from a standalone issuer URL by parsing the
|
|
353
380
|
* realm and base URL. Useful when migrating from the legacy
|
|
@@ -430,4 +457,4 @@ declare class AuthClient {
|
|
|
430
457
|
private resolveScope;
|
|
431
458
|
}
|
|
432
459
|
|
|
433
|
-
export {
|
|
460
|
+
export { AuthApiClient as A, type DirectKcOptions as D, type ForgotPasswordRequest as F, type InactivityStore as I, type LoginOptions as L, type OtpLoginRequest as O, type PasswordLoginRequest as P, type ResetPasswordRequest as R, type TokenStorage as T, type AuthSessionInfo as a, AuthClient as b, type AuthTokens as c, type AuthApiClientOptions as d, type AuthClientCollaborators as e, type AuthClientConfig as f, type AuthClientFromIssuerInput as g, AuthEventEmitter as h, type AuthEventListener as i, type AuthEventName as j, type AuthEventUnsubscribe as k, InactivityTracker as l, type InactivityTrackerOptions as m, type LogoutOptions as n, type RawAuthLoginResponse as o, type RefreshFn as p, RefreshInterceptor as q, type RefreshInterceptorOptions as r };
|
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
import { H as HttpClient, T as TokenResponse } from './TokenResponse-CY1CaU2l.js';
|
|
2
|
+
|
|
1
3
|
/**
|
|
2
4
|
* Tiny dependency-free event emitter for auth lifecycle events.
|
|
3
5
|
*
|
|
@@ -19,39 +21,6 @@ declare class AuthEventEmitter {
|
|
|
19
21
|
clear(): void;
|
|
20
22
|
}
|
|
21
23
|
|
|
22
|
-
/**
|
|
23
|
-
* Minimal HTTP transport the package depends on.
|
|
24
|
-
*
|
|
25
|
-
* `AuthClient` orchestrates token-related HTTP calls (login, refresh, logout,
|
|
26
|
-
* password reset) but doesn't import `fetch` directly — keeping the package
|
|
27
|
-
* runtime-agnostic. Consumers wire native fetch, axios, ky, or whatever their
|
|
28
|
-
* platform exposes.
|
|
29
|
-
*/
|
|
30
|
-
interface HttpRequest {
|
|
31
|
-
url: string;
|
|
32
|
-
method: 'GET' | 'POST' | 'DELETE';
|
|
33
|
-
headers?: Record<string, string>;
|
|
34
|
-
/** When set, body is sent as the request body; serialization is the caller's job. */
|
|
35
|
-
body?: string;
|
|
36
|
-
/** Browser fetch only — pass through `credentials: 'include'` for cookie auth. */
|
|
37
|
-
credentials?: 'include' | 'same-origin' | 'omit';
|
|
38
|
-
}
|
|
39
|
-
interface HttpResponse {
|
|
40
|
-
status: number;
|
|
41
|
-
ok: boolean;
|
|
42
|
-
/** Parsed body (already JSON-decoded). `undefined` for 204 / empty bodies. */
|
|
43
|
-
data?: unknown;
|
|
44
|
-
}
|
|
45
|
-
type HttpClient = (request: HttpRequest) => Promise<HttpResponse>;
|
|
46
|
-
/**
|
|
47
|
-
* Wrap the platform's native `fetch` into the package's `HttpClient` shape.
|
|
48
|
-
* Decoded JSON when `Content-Type` is JSON, otherwise leaves data undefined.
|
|
49
|
-
*
|
|
50
|
-
* Errors thrown by `fetch` (network / abort) are NOT swallowed — callers
|
|
51
|
-
* decide whether to treat them as session-ending.
|
|
52
|
-
*/
|
|
53
|
-
declare function createFetchHttpClient(fetchImpl: typeof fetch): HttpClient;
|
|
54
|
-
|
|
55
24
|
/**
|
|
56
25
|
* Backend session record returned by `GET /me/sessions`.
|
|
57
26
|
*
|
|
@@ -328,6 +297,34 @@ interface AuthClientCollaborators {
|
|
|
328
297
|
interceptor?: RefreshInterceptor;
|
|
329
298
|
inactivityTracker?: InactivityTracker;
|
|
330
299
|
events?: AuthEventEmitter;
|
|
300
|
+
/**
|
|
301
|
+
* Observability hook fired when a fresh token bundle has been acquired
|
|
302
|
+
* (any login path: OTP, password, or direct-KC PKCE). For app-side
|
|
303
|
+
* analytics/logging only — NOT for BFF integration (Phase 2 designs that
|
|
304
|
+
* fresh).
|
|
305
|
+
*/
|
|
306
|
+
onTokenAcquired?: (tokens: AuthTokens) => void;
|
|
307
|
+
/**
|
|
308
|
+
* Observability hook fired when an existing token bundle has been
|
|
309
|
+
* refreshed. For app-side analytics/logging only.
|
|
310
|
+
*/
|
|
311
|
+
onTokenRefreshed?: (tokens: AuthTokens) => void;
|
|
312
|
+
}
|
|
313
|
+
/**
|
|
314
|
+
* Direct-to-KC (PKCE) routing flag added in v2.1.0.
|
|
315
|
+
*
|
|
316
|
+
* When `true`, `AuthClient` consumers can route their PKCE auth code through
|
|
317
|
+
* the shared OIDC primitives (`exchangeAuthorizationCodeViaOidc`,
|
|
318
|
+
* `refreshTokensViaOidc`) instead of the proxied identity-api `/auth/login`
|
|
319
|
+
* + `/auth/refresh` flow.
|
|
320
|
+
*
|
|
321
|
+
* Default `false` — v2.0 behavior unchanged.
|
|
322
|
+
*
|
|
323
|
+
* The flag is read-only at runtime (`isDirectMode()`) so apps can render
|
|
324
|
+
* conditionally on whether they've opted in.
|
|
325
|
+
*/
|
|
326
|
+
interface DirectKcOptions {
|
|
327
|
+
useDirectKcAuth?: boolean;
|
|
331
328
|
}
|
|
332
329
|
interface LoginOptions {
|
|
333
330
|
/** When true, request `offline_access` scope so the IdP issues a long-lived refresh token. */
|
|
@@ -339,15 +336,45 @@ interface LogoutOptions {
|
|
|
339
336
|
}
|
|
340
337
|
declare class AuthClient {
|
|
341
338
|
private readonly config;
|
|
339
|
+
private readonly directKcAuth;
|
|
342
340
|
private readonly tokenStorage;
|
|
343
341
|
private readonly api;
|
|
344
342
|
private readonly interceptor;
|
|
345
343
|
private readonly inactivityTracker;
|
|
346
344
|
private readonly events;
|
|
345
|
+
private readonly onTokenAcquired;
|
|
346
|
+
private readonly onTokenRefreshed;
|
|
347
347
|
/**
|
|
348
348
|
* @throws Error when `baseUrl`, `realm`, or `clientId` is missing or empty.
|
|
349
349
|
*/
|
|
350
|
-
constructor(config: AuthClientConfig, storage: TokenStorage, collaborators?: AuthClientCollaborators);
|
|
350
|
+
constructor(config: AuthClientConfig & DirectKcOptions, storage: TokenStorage, collaborators?: AuthClientCollaborators);
|
|
351
|
+
/**
|
|
352
|
+
* Whether this client is configured to route auth flows directly to
|
|
353
|
+
* Keycloak (v2.1.0 direct-KC path) instead of through the proxied
|
|
354
|
+
* identity-api `/auth/*` endpoints.
|
|
355
|
+
*
|
|
356
|
+
* Apps can render conditionally on this — e.g. to swap a login form for
|
|
357
|
+
* a "Sign in with Keycloak" redirect button.
|
|
358
|
+
*/
|
|
359
|
+
isDirectMode(): boolean;
|
|
360
|
+
/**
|
|
361
|
+
* Persist a token bundle produced by an external flow (e.g. the
|
|
362
|
+
* app-side `useKeycloakExchange` hook that consumes the shared
|
|
363
|
+
* `exchangeAuthorizationCode` primitive). Fires `onTokenAcquired` after
|
|
364
|
+
* persistence and marks the inactivity tracker active.
|
|
365
|
+
*
|
|
366
|
+
* Designed for the v2.1.0 direct-KC path where the PKCE code exchange
|
|
367
|
+
* happens in the app's React-Query hook (which needs `useDispatch`/etc.)
|
|
368
|
+
* but the token persistence + observability should still flow through
|
|
369
|
+
* the shared client.
|
|
370
|
+
*/
|
|
371
|
+
acceptDirectKcTokens(response: TokenResponse): Promise<AuthTokens>;
|
|
372
|
+
/**
|
|
373
|
+
* Same as {@link acceptDirectKcTokens} but fires `onTokenRefreshed`.
|
|
374
|
+
* Use after a `refreshAccessToken()` swap to keep observability counts
|
|
375
|
+
* separated between "fresh login" and "silent refresh".
|
|
376
|
+
*/
|
|
377
|
+
acceptDirectKcRefresh(response: TokenResponse): Promise<AuthTokens>;
|
|
351
378
|
/**
|
|
352
379
|
* Build an {@link AuthClient} from a standalone issuer URL by parsing the
|
|
353
380
|
* realm and base URL. Useful when migrating from the legacy
|
|
@@ -430,4 +457,4 @@ declare class AuthClient {
|
|
|
430
457
|
private resolveScope;
|
|
431
458
|
}
|
|
432
459
|
|
|
433
|
-
export {
|
|
460
|
+
export { AuthApiClient as A, type DirectKcOptions as D, type ForgotPasswordRequest as F, type InactivityStore as I, type LoginOptions as L, type OtpLoginRequest as O, type PasswordLoginRequest as P, type ResetPasswordRequest as R, type TokenStorage as T, type AuthSessionInfo as a, AuthClient as b, type AuthTokens as c, type AuthApiClientOptions as d, type AuthClientCollaborators as e, type AuthClientConfig as f, type AuthClientFromIssuerInput as g, AuthEventEmitter as h, type AuthEventListener as i, type AuthEventName as j, type AuthEventUnsubscribe as k, InactivityTracker as l, type InactivityTrackerOptions as m, type LogoutOptions as n, type RawAuthLoginResponse as o, type RefreshFn as p, RefreshInterceptor as q, type RefreshInterceptorOptions as r };
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Minimal HTTP transport the package depends on.
|
|
3
|
+
*
|
|
4
|
+
* `AuthClient` orchestrates token-related HTTP calls (login, refresh, logout,
|
|
5
|
+
* password reset) but doesn't import `fetch` directly — keeping the package
|
|
6
|
+
* runtime-agnostic. Consumers wire native fetch, axios, ky, or whatever their
|
|
7
|
+
* platform exposes.
|
|
8
|
+
*/
|
|
9
|
+
interface HttpRequest {
|
|
10
|
+
url: string;
|
|
11
|
+
method: 'GET' | 'POST' | 'DELETE';
|
|
12
|
+
headers?: Record<string, string>;
|
|
13
|
+
/** When set, body is sent as the request body; serialization is the caller's job. */
|
|
14
|
+
body?: string;
|
|
15
|
+
/** Browser fetch only — pass through `credentials: 'include'` for cookie auth. */
|
|
16
|
+
credentials?: 'include' | 'same-origin' | 'omit';
|
|
17
|
+
}
|
|
18
|
+
interface HttpResponse {
|
|
19
|
+
status: number;
|
|
20
|
+
ok: boolean;
|
|
21
|
+
/** Parsed body (already JSON-decoded). `undefined` for 204 / empty bodies. */
|
|
22
|
+
data?: unknown;
|
|
23
|
+
}
|
|
24
|
+
type HttpClient = (request: HttpRequest) => Promise<HttpResponse>;
|
|
25
|
+
/**
|
|
26
|
+
* Wrap the platform's native `fetch` into the package's `HttpClient` shape.
|
|
27
|
+
* Decoded JSON when `Content-Type` is JSON, otherwise leaves data undefined.
|
|
28
|
+
*
|
|
29
|
+
* Errors thrown by `fetch` (network / abort) are NOT swallowed — callers
|
|
30
|
+
* decide whether to treat them as session-ending.
|
|
31
|
+
*/
|
|
32
|
+
declare function createFetchHttpClient(fetchImpl: typeof fetch): HttpClient;
|
|
33
|
+
|
|
34
|
+
/**
|
|
35
|
+
* Raw token endpoint response (snake_case, OIDC standard).
|
|
36
|
+
*/
|
|
37
|
+
interface RawTokenResponse {
|
|
38
|
+
access_token: string;
|
|
39
|
+
refresh_token?: string;
|
|
40
|
+
id_token?: string;
|
|
41
|
+
expires_in?: number;
|
|
42
|
+
token_type?: string;
|
|
43
|
+
scope?: string;
|
|
44
|
+
[key: string]: unknown;
|
|
45
|
+
}
|
|
46
|
+
/**
|
|
47
|
+
* Application-friendly camelCase view of a token endpoint response.
|
|
48
|
+
*/
|
|
49
|
+
interface TokenResponse {
|
|
50
|
+
accessToken: string;
|
|
51
|
+
refreshToken?: string;
|
|
52
|
+
idToken?: string;
|
|
53
|
+
/** Seconds until expiry, as returned by Keycloak. */
|
|
54
|
+
expiresIn?: number;
|
|
55
|
+
tokenType?: string;
|
|
56
|
+
scope?: string;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
export { type HttpClient as H, type RawTokenResponse as R, type TokenResponse as T, type HttpRequest as a, type HttpResponse as b, createFetchHttpClient as c };
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Minimal HTTP transport the package depends on.
|
|
3
|
+
*
|
|
4
|
+
* `AuthClient` orchestrates token-related HTTP calls (login, refresh, logout,
|
|
5
|
+
* password reset) but doesn't import `fetch` directly — keeping the package
|
|
6
|
+
* runtime-agnostic. Consumers wire native fetch, axios, ky, or whatever their
|
|
7
|
+
* platform exposes.
|
|
8
|
+
*/
|
|
9
|
+
interface HttpRequest {
|
|
10
|
+
url: string;
|
|
11
|
+
method: 'GET' | 'POST' | 'DELETE';
|
|
12
|
+
headers?: Record<string, string>;
|
|
13
|
+
/** When set, body is sent as the request body; serialization is the caller's job. */
|
|
14
|
+
body?: string;
|
|
15
|
+
/** Browser fetch only — pass through `credentials: 'include'` for cookie auth. */
|
|
16
|
+
credentials?: 'include' | 'same-origin' | 'omit';
|
|
17
|
+
}
|
|
18
|
+
interface HttpResponse {
|
|
19
|
+
status: number;
|
|
20
|
+
ok: boolean;
|
|
21
|
+
/** Parsed body (already JSON-decoded). `undefined` for 204 / empty bodies. */
|
|
22
|
+
data?: unknown;
|
|
23
|
+
}
|
|
24
|
+
type HttpClient = (request: HttpRequest) => Promise<HttpResponse>;
|
|
25
|
+
/**
|
|
26
|
+
* Wrap the platform's native `fetch` into the package's `HttpClient` shape.
|
|
27
|
+
* Decoded JSON when `Content-Type` is JSON, otherwise leaves data undefined.
|
|
28
|
+
*
|
|
29
|
+
* Errors thrown by `fetch` (network / abort) are NOT swallowed — callers
|
|
30
|
+
* decide whether to treat them as session-ending.
|
|
31
|
+
*/
|
|
32
|
+
declare function createFetchHttpClient(fetchImpl: typeof fetch): HttpClient;
|
|
33
|
+
|
|
34
|
+
/**
|
|
35
|
+
* Raw token endpoint response (snake_case, OIDC standard).
|
|
36
|
+
*/
|
|
37
|
+
interface RawTokenResponse {
|
|
38
|
+
access_token: string;
|
|
39
|
+
refresh_token?: string;
|
|
40
|
+
id_token?: string;
|
|
41
|
+
expires_in?: number;
|
|
42
|
+
token_type?: string;
|
|
43
|
+
scope?: string;
|
|
44
|
+
[key: string]: unknown;
|
|
45
|
+
}
|
|
46
|
+
/**
|
|
47
|
+
* Application-friendly camelCase view of a token endpoint response.
|
|
48
|
+
*/
|
|
49
|
+
interface TokenResponse {
|
|
50
|
+
accessToken: string;
|
|
51
|
+
refreshToken?: string;
|
|
52
|
+
idToken?: string;
|
|
53
|
+
/** Seconds until expiry, as returned by Keycloak. */
|
|
54
|
+
expiresIn?: number;
|
|
55
|
+
tokenType?: string;
|
|
56
|
+
scope?: string;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
export { type HttpClient as H, type RawTokenResponse as R, type TokenResponse as T, type HttpRequest as a, type HttpResponse as b, createFetchHttpClient as c };
|
package/dist/index.d.mts
CHANGED
|
@@ -1,5 +1,8 @@
|
|
|
1
|
-
import { T as TokenStorage,
|
|
2
|
-
export {
|
|
1
|
+
import { T as TokenStorage, c as AuthTokens } from './AuthClient-BGr8L03W.mjs';
|
|
2
|
+
export { A as AuthApiClient, d as AuthApiClientOptions, b as AuthClient, e as AuthClientCollaborators, f as AuthClientConfig, g as AuthClientFromIssuerInput, h as AuthEventEmitter, i as AuthEventListener, j as AuthEventName, k as AuthEventUnsubscribe, a as AuthSessionInfo, D as DirectKcOptions, F as ForgotPasswordRequest, I as InactivityStore, l as InactivityTracker, m as InactivityTrackerOptions, L as LoginOptions, n as LogoutOptions, O as OtpLoginRequest, P as PasswordLoginRequest, o as RawAuthLoginResponse, p as RefreshFn, q as RefreshInterceptor, r as RefreshInterceptorOptions, R as ResetPasswordRequest } from './AuthClient-BGr8L03W.mjs';
|
|
3
|
+
export { ExchangeAuthorizationCodeInput, FetchDiscoveryDocumentInput, OidcDiscoveryDocument, PkcePair, RefreshAccessTokenInput, clearDiscoveryCache, deriveCodeChallenge, exchangeAuthorizationCode, fetchDiscoveryDocument, generateCodeVerifier, generatePkcePair, refreshAccessToken } from './oidc/index.mjs';
|
|
4
|
+
import { R as RawTokenResponse, T as TokenResponse } from './TokenResponse-CY1CaU2l.mjs';
|
|
5
|
+
export { H as HttpClient, a as HttpRequest, b as HttpResponse, c as createFetchHttpClient } from './TokenResponse-CY1CaU2l.mjs';
|
|
3
6
|
|
|
4
7
|
/**
|
|
5
8
|
* Roles emitted by Keycloak realms in the dloizides.com portfolio.
|
|
@@ -65,31 +68,6 @@ interface NormalizedUser {
|
|
|
65
68
|
raw?: KeycloakUserInfo;
|
|
66
69
|
}
|
|
67
70
|
|
|
68
|
-
/**
|
|
69
|
-
* Raw token endpoint response (snake_case, OIDC standard).
|
|
70
|
-
*/
|
|
71
|
-
interface RawTokenResponse {
|
|
72
|
-
access_token: string;
|
|
73
|
-
refresh_token?: string;
|
|
74
|
-
id_token?: string;
|
|
75
|
-
expires_in?: number;
|
|
76
|
-
token_type?: string;
|
|
77
|
-
scope?: string;
|
|
78
|
-
[key: string]: unknown;
|
|
79
|
-
}
|
|
80
|
-
/**
|
|
81
|
-
* Application-friendly camelCase view of a token endpoint response.
|
|
82
|
-
*/
|
|
83
|
-
interface TokenResponse {
|
|
84
|
-
accessToken: string;
|
|
85
|
-
refreshToken?: string;
|
|
86
|
-
idToken?: string;
|
|
87
|
-
/** Seconds until expiry, as returned by Keycloak. */
|
|
88
|
-
expiresIn?: number;
|
|
89
|
-
tokenType?: string;
|
|
90
|
-
scope?: string;
|
|
91
|
-
}
|
|
92
|
-
|
|
93
71
|
/**
|
|
94
72
|
* Subset of `Storage` we actually use. Lets callers inject `localStorage`,
|
|
95
73
|
* `sessionStorage`, or any compatible polyfill.
|
|
@@ -510,4 +488,4 @@ declare function normalizeTokenResponse(raw: RawTokenResponse): TokenResponse;
|
|
|
510
488
|
*/
|
|
511
489
|
declare function tokenResponseToAuthTokens(response: TokenResponse, now?: number): AuthTokens;
|
|
512
490
|
|
|
513
|
-
export { AuthTokens, type AuthorizationCodeBodyInput, type AuthorizationResponseLike, type AuthorizationUrlInput, type BiometricFlagStore, BiometricGate, type BiometricGateLike, type BiometricGateOptions, BrowserStorageTokenStorage, type BrowserStorageTokenStorageOptions, CookieTokenStorage, InMemoryTokenStorage, KeycloakRoles, type KeycloakUserInfo, type LocalAuthLike, type NormalizedUser,
|
|
491
|
+
export { AuthTokens, type AuthorizationCodeBodyInput, type AuthorizationResponseLike, type AuthorizationUrlInput, type BiometricFlagStore, BiometricGate, type BiometricGateLike, type BiometricGateOptions, BrowserStorageTokenStorage, type BrowserStorageTokenStorageOptions, CookieTokenStorage, InMemoryTokenStorage, KeycloakRoles, type KeycloakUserInfo, type LocalAuthLike, type NormalizedUser, RawTokenResponse, type RefreshTokenBodyInput, type SecureStoreLike, SecureStoreTokenStorage, type SecureStoreTokenStorageOptions, type StorageLike, TokenResponse, TokenStorage, buildAuthorizationCodeBody, buildAuthorizationEndpoint, buildAuthorizationUrl, buildIssuerUrl, buildLogoutEndpoint, buildRefreshTokenBody, buildTokenEndpoint, buildUserInfoEndpoint, computeExpiresAt, decodeJwt, extractAuthCode, isKeycloakRole, isTokenExpired, normalizeKeycloakUser, normalizeTokenResponse, parseBaseUrlFromIssuer, parseRealmFromIssuer, tokenResponseToAuthTokens };
|
package/dist/index.d.ts
CHANGED
|
@@ -1,5 +1,8 @@
|
|
|
1
|
-
import { T as TokenStorage,
|
|
2
|
-
export {
|
|
1
|
+
import { T as TokenStorage, c as AuthTokens } from './AuthClient-D95OMajD.js';
|
|
2
|
+
export { A as AuthApiClient, d as AuthApiClientOptions, b as AuthClient, e as AuthClientCollaborators, f as AuthClientConfig, g as AuthClientFromIssuerInput, h as AuthEventEmitter, i as AuthEventListener, j as AuthEventName, k as AuthEventUnsubscribe, a as AuthSessionInfo, D as DirectKcOptions, F as ForgotPasswordRequest, I as InactivityStore, l as InactivityTracker, m as InactivityTrackerOptions, L as LoginOptions, n as LogoutOptions, O as OtpLoginRequest, P as PasswordLoginRequest, o as RawAuthLoginResponse, p as RefreshFn, q as RefreshInterceptor, r as RefreshInterceptorOptions, R as ResetPasswordRequest } from './AuthClient-D95OMajD.js';
|
|
3
|
+
export { ExchangeAuthorizationCodeInput, FetchDiscoveryDocumentInput, OidcDiscoveryDocument, PkcePair, RefreshAccessTokenInput, clearDiscoveryCache, deriveCodeChallenge, exchangeAuthorizationCode, fetchDiscoveryDocument, generateCodeVerifier, generatePkcePair, refreshAccessToken } from './oidc/index.js';
|
|
4
|
+
import { R as RawTokenResponse, T as TokenResponse } from './TokenResponse-CY1CaU2l.js';
|
|
5
|
+
export { H as HttpClient, a as HttpRequest, b as HttpResponse, c as createFetchHttpClient } from './TokenResponse-CY1CaU2l.js';
|
|
3
6
|
|
|
4
7
|
/**
|
|
5
8
|
* Roles emitted by Keycloak realms in the dloizides.com portfolio.
|
|
@@ -65,31 +68,6 @@ interface NormalizedUser {
|
|
|
65
68
|
raw?: KeycloakUserInfo;
|
|
66
69
|
}
|
|
67
70
|
|
|
68
|
-
/**
|
|
69
|
-
* Raw token endpoint response (snake_case, OIDC standard).
|
|
70
|
-
*/
|
|
71
|
-
interface RawTokenResponse {
|
|
72
|
-
access_token: string;
|
|
73
|
-
refresh_token?: string;
|
|
74
|
-
id_token?: string;
|
|
75
|
-
expires_in?: number;
|
|
76
|
-
token_type?: string;
|
|
77
|
-
scope?: string;
|
|
78
|
-
[key: string]: unknown;
|
|
79
|
-
}
|
|
80
|
-
/**
|
|
81
|
-
* Application-friendly camelCase view of a token endpoint response.
|
|
82
|
-
*/
|
|
83
|
-
interface TokenResponse {
|
|
84
|
-
accessToken: string;
|
|
85
|
-
refreshToken?: string;
|
|
86
|
-
idToken?: string;
|
|
87
|
-
/** Seconds until expiry, as returned by Keycloak. */
|
|
88
|
-
expiresIn?: number;
|
|
89
|
-
tokenType?: string;
|
|
90
|
-
scope?: string;
|
|
91
|
-
}
|
|
92
|
-
|
|
93
71
|
/**
|
|
94
72
|
* Subset of `Storage` we actually use. Lets callers inject `localStorage`,
|
|
95
73
|
* `sessionStorage`, or any compatible polyfill.
|
|
@@ -510,4 +488,4 @@ declare function normalizeTokenResponse(raw: RawTokenResponse): TokenResponse;
|
|
|
510
488
|
*/
|
|
511
489
|
declare function tokenResponseToAuthTokens(response: TokenResponse, now?: number): AuthTokens;
|
|
512
490
|
|
|
513
|
-
export { AuthTokens, type AuthorizationCodeBodyInput, type AuthorizationResponseLike, type AuthorizationUrlInput, type BiometricFlagStore, BiometricGate, type BiometricGateLike, type BiometricGateOptions, BrowserStorageTokenStorage, type BrowserStorageTokenStorageOptions, CookieTokenStorage, InMemoryTokenStorage, KeycloakRoles, type KeycloakUserInfo, type LocalAuthLike, type NormalizedUser,
|
|
491
|
+
export { AuthTokens, type AuthorizationCodeBodyInput, type AuthorizationResponseLike, type AuthorizationUrlInput, type BiometricFlagStore, BiometricGate, type BiometricGateLike, type BiometricGateOptions, BrowserStorageTokenStorage, type BrowserStorageTokenStorageOptions, CookieTokenStorage, InMemoryTokenStorage, KeycloakRoles, type KeycloakUserInfo, type LocalAuthLike, type NormalizedUser, RawTokenResponse, type RefreshTokenBodyInput, type SecureStoreLike, SecureStoreTokenStorage, type SecureStoreTokenStorageOptions, type StorageLike, TokenResponse, TokenStorage, buildAuthorizationCodeBody, buildAuthorizationEndpoint, buildAuthorizationUrl, buildIssuerUrl, buildLogoutEndpoint, buildRefreshTokenBody, buildTokenEndpoint, buildUserInfoEndpoint, computeExpiresAt, decodeJwt, extractAuthCode, isKeycloakRole, isTokenExpired, normalizeKeycloakUser, normalizeTokenResponse, parseBaseUrlFromIssuer, parseRealmFromIssuer, tokenResponseToAuthTokens };
|