@dloizides/auth-client 2.1.0 → 3.2.1
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 +67 -0
- package/README.md +37 -1
- package/dist/{AuthClient-D95OMajD.d.ts → AuthClient-Cv7btBX0.d.ts} +1 -1
- package/dist/{AuthClient-BGr8L03W.d.mts → AuthClient-D8Ul-aGa.d.mts} +1 -1
- package/dist/index.d.mts +181 -5
- package/dist/index.d.ts +181 -5
- package/dist/index.js +174 -0
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +174 -1
- package/dist/index.mjs.map +1 -1
- package/dist/react.d.mts +1 -1
- package/dist/react.d.ts +1 -1
- package/package.json +124 -124
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,72 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 3.2.0 (2026-05-22)
|
|
4
|
+
|
|
5
|
+
Additive release for Phase 3d of the unified-auth plan — event-scoped PIN
|
|
6
|
+
login. Extends `BffAuthClient` with the browser-facing PIN call so the new
|
|
7
|
+
`<PinForm>` in `@dloizides/auth-web` has a same-origin client. No breaking
|
|
8
|
+
changes.
|
|
9
|
+
|
|
10
|
+
### Added
|
|
11
|
+
|
|
12
|
+
- `BffAuthClient.pinLogin({ pin, eventExternalId })` → `POST /bff/pin/login`.
|
|
13
|
+
The BFF runs the event-scoped PIN direct-grant against Keycloak server-side
|
|
14
|
+
(the `(event, pin)` pair resolves to the staff member's KC account + their
|
|
15
|
+
event-scoped role) and sets the httpOnly session cookie. Returns the
|
|
16
|
+
sanitised `BffUser`, exactly like `login` / `verifyOtp`. Throws on a non-2xx
|
|
17
|
+
(`401` for a bad / expired / locked-out PIN or an unknown event, `501` when
|
|
18
|
+
PIN login is not an enabled method). Carries the `X-BFF-Csrf` header like
|
|
19
|
+
every other state-changing call. No `username` / `password` ever leaves the
|
|
20
|
+
browser.
|
|
21
|
+
- Type: `BffPinLoginRequest`.
|
|
22
|
+
|
|
23
|
+
## 3.1.0 (2026-05-22)
|
|
24
|
+
|
|
25
|
+
Additive release for Phase 2d of the unified-auth plan — email-OTP. Extends
|
|
26
|
+
`BffAuthClient` with the two browser-facing OTP calls so the new `<OtpForm>` in
|
|
27
|
+
`@dloizides/auth-web` has a same-origin client. No breaking changes.
|
|
28
|
+
|
|
29
|
+
### Added
|
|
30
|
+
|
|
31
|
+
- `BffAuthClient.requestOtp({ identifier })` → `POST /bff/otp/request`. The BFF
|
|
32
|
+
proxies to TenantService, which emails a short-TTL code. The endpoint is
|
|
33
|
+
anti-enumeration (a `200` is the normal path), so the method **returns** the
|
|
34
|
+
relayed `{ success, expiresIn, code }` body — the UI uses `expiresIn` for a
|
|
35
|
+
countdown. It still throws on a non-2xx (`501` OTP not enabled, `502` upstream
|
|
36
|
+
down). Carries the `X-BFF-Csrf` header like every other state-changing call.
|
|
37
|
+
- `BffAuthClient.verifyOtp({ username, otp })` → `POST /bff/otp/verify`. The BFF
|
|
38
|
+
runs the OTP direct-grant against Keycloak server-side and sets the httpOnly
|
|
39
|
+
session cookie. Returns the sanitised `BffUser`, exactly like `login`. Throws
|
|
40
|
+
on a non-2xx (e.g. `401` for a bad / expired code).
|
|
41
|
+
- Types: `BffOtpRequestRequest`, `BffOtpVerifyRequest`, `BffOtpRequestResult`.
|
|
42
|
+
|
|
43
|
+
## 3.0.0 (2026-05-19)
|
|
44
|
+
|
|
45
|
+
Major release for Phase 2 of the identity-hardening initiative. Adds the
|
|
46
|
+
shared `BffAuthClient` — the same-origin client for a per-app
|
|
47
|
+
**Backend-For-Frontend** (`bff-katalogos`, `bff-erevna`). The BFF terminates
|
|
48
|
+
authentication server-side: the browser holds only an opaque httpOnly session
|
|
49
|
+
cookie, never a token.
|
|
50
|
+
|
|
51
|
+
This is the **new recommended auth surface**. The major bump signals that
|
|
52
|
+
recommendation — it is **not** a breaking change: every v2.x export
|
|
53
|
+
(`AuthClient`, the direct-KC ROPC adapters, `useDirectKcAuth`, the OIDC
|
|
54
|
+
primitives, storage adapters, hooks) remains and is unchanged. BaseClient
|
|
55
|
+
still consumes the direct-KC path; it is removed in a later phase.
|
|
56
|
+
|
|
57
|
+
### Added
|
|
58
|
+
|
|
59
|
+
- `BffAuthClient` — same-origin client for a per-app BFF. Methods:
|
|
60
|
+
`login({username,password})` → `POST /bff/login`; `logout()` →
|
|
61
|
+
`POST /bff/logout`; `getCurrentUser()` → `GET /bff/me`; `register(...)`,
|
|
62
|
+
`forgotPassword(...)`, `resetPassword(...)` → the matching `/bff/*`
|
|
63
|
+
endpoints. Every call is a same-origin `fetch` with
|
|
64
|
+
`credentials: 'include'`; state-changing calls carry the `X-BFF-Csrf: 1`
|
|
65
|
+
header the `Bff.AspNetCore` anti-forgery middleware requires. Does **no
|
|
66
|
+
token handling** — the BFF owns tokens, the browser owns only the cookie.
|
|
67
|
+
- Types: `BffAuthClientOptions`, `BffLoginRequest`, `BffRegisterRequest`,
|
|
68
|
+
`BffForgotPasswordRequest`, `BffResetPasswordRequest`, `BffUser`.
|
|
69
|
+
|
|
3
70
|
## 2.1.0 (2026-05-17)
|
|
4
71
|
|
|
5
72
|
Additive release. Lays the groundwork for the "shrink identity service"
|
package/README.md
CHANGED
|
@@ -119,6 +119,41 @@ const storage = new SecureStoreTokenStorage({
|
|
|
119
119
|
await biometricGate.hydrate();
|
|
120
120
|
```
|
|
121
121
|
|
|
122
|
+
## BFF auth (v3 — recommended)
|
|
123
|
+
|
|
124
|
+
`BffAuthClient` is the same-origin client for a per-app **Backend-For-Frontend**
|
|
125
|
+
(`bff-katalogos`, `bff-erevna`). The BFF terminates authentication
|
|
126
|
+
server-side: it does ROPC against Keycloak with a confidential client, stores
|
|
127
|
+
the tokens in a Redis vault, and hands the browser only an opaque httpOnly
|
|
128
|
+
session cookie. The SPA never sees a token — an XSS cannot exfiltrate one.
|
|
129
|
+
|
|
130
|
+
`BffAuthClient` does **no token handling**: every call is a same-origin
|
|
131
|
+
`fetch` with `credentials: 'include'`, and state-changing calls carry the
|
|
132
|
+
`X-BFF-Csrf: 1` header the BFF anti-forgery middleware requires.
|
|
133
|
+
|
|
134
|
+
```ts
|
|
135
|
+
import { BffAuthClient, createFetchHttpClient } from '@dloizides/auth-client';
|
|
136
|
+
|
|
137
|
+
const bff = new BffAuthClient({
|
|
138
|
+
http: createFetchHttpClient(window.fetch.bind(window)),
|
|
139
|
+
// baseUrl defaults to '' (same-origin) — the production wiring.
|
|
140
|
+
});
|
|
141
|
+
|
|
142
|
+
// Login — the BFF does ROPC server-side and sets the session cookie.
|
|
143
|
+
const user = await bff.login({ username, password });
|
|
144
|
+
|
|
145
|
+
// Bootstrap on app load — null when there is no live session.
|
|
146
|
+
const current = await bff.getCurrentUser();
|
|
147
|
+
|
|
148
|
+
await bff.register({ firstName, lastName, username, email, password, tenantName });
|
|
149
|
+
await bff.forgotPassword({ email, resetUrlTemplate });
|
|
150
|
+
await bff.resetPassword({ token, newPassword });
|
|
151
|
+
await bff.logout();
|
|
152
|
+
```
|
|
153
|
+
|
|
154
|
+
The direct-KC `AuthClient` / ROPC surface below is retained for consumers not
|
|
155
|
+
yet on a BFF; it is deprecated and removed once every app has migrated.
|
|
156
|
+
|
|
122
157
|
## React Query hooks
|
|
123
158
|
|
|
124
159
|
```ts
|
|
@@ -156,7 +191,8 @@ auth.on('sessionExpired', () => {
|
|
|
156
191
|
|
|
157
192
|
### Core (`@dloizides/auth-client`)
|
|
158
193
|
|
|
159
|
-
- `
|
|
194
|
+
- `BffAuthClient` — same-origin client for a per-app Backend-For-Frontend. `login()`, `logout()`, `getCurrentUser()`, `register()`, `forgotPassword()`, `resetPassword()`. No token handling — the BFF owns tokens, the browser owns only an httpOnly cookie. **The recommended auth surface (v3).**
|
|
195
|
+
- `AuthClient` — realm-aware orchestrator. `init()`, `refresh()`, `loginWithOtp()`, `loginWithPassword()`, `logout({ everywhere })`, `requestPasswordReset()`, `confirmPasswordReset()`, plus the v1 surface (`getAccessToken`, `getTokens`, `setTokens`, `clearTokens`, `buildAuthorizationUrl`, etc.). Direct-KC ROPC; deprecated in favour of `BffAuthClient`.
|
|
160
196
|
- `AuthApiClient` — typed wrapper for IdentityService auth endpoints.
|
|
161
197
|
- `AuthEventEmitter` — `sessionExpired` event.
|
|
162
198
|
- `RefreshInterceptor` — single-flight refresh queue.
|
|
@@ -457,4 +457,4 @@ declare class AuthClient {
|
|
|
457
457
|
private resolveScope;
|
|
458
458
|
}
|
|
459
459
|
|
|
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
|
|
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 RawAuthLoginResponse as R, type TokenStorage as T, type AuthApiClientOptions as a, AuthClient as b, type AuthClientCollaborators as c, type AuthClientConfig as d, type AuthClientFromIssuerInput as e, AuthEventEmitter as f, type AuthEventListener as g, type AuthEventName as h, type AuthEventUnsubscribe as i, type AuthSessionInfo as j, type AuthTokens as k, InactivityTracker as l, type InactivityTrackerOptions as m, type LogoutOptions as n, type RefreshFn as o, RefreshInterceptor as p, type RefreshInterceptorOptions as q, type ResetPasswordRequest as r };
|
|
@@ -457,4 +457,4 @@ declare class AuthClient {
|
|
|
457
457
|
private resolveScope;
|
|
458
458
|
}
|
|
459
459
|
|
|
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
|
|
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 RawAuthLoginResponse as R, type TokenStorage as T, type AuthApiClientOptions as a, AuthClient as b, type AuthClientCollaborators as c, type AuthClientConfig as d, type AuthClientFromIssuerInput as e, AuthEventEmitter as f, type AuthEventListener as g, type AuthEventName as h, type AuthEventUnsubscribe as i, type AuthSessionInfo as j, type AuthTokens as k, InactivityTracker as l, type InactivityTrackerOptions as m, type LogoutOptions as n, type RefreshFn as o, RefreshInterceptor as p, type RefreshInterceptorOptions as q, type ResetPasswordRequest as r };
|
package/dist/index.d.mts
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
import { T as TokenStorage,
|
|
2
|
-
export { A as AuthApiClient,
|
|
1
|
+
import { T as TokenStorage, k as AuthTokens } from './AuthClient-D8Ul-aGa.mjs';
|
|
2
|
+
export { A as AuthApiClient, a as AuthApiClientOptions, b as AuthClient, c as AuthClientCollaborators, d as AuthClientConfig, e as AuthClientFromIssuerInput, f as AuthEventEmitter, g as AuthEventListener, h as AuthEventName, i as AuthEventUnsubscribe, j 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, R as RawAuthLoginResponse, o as RefreshFn, p as RefreshInterceptor, q as RefreshInterceptorOptions, r as ResetPasswordRequest } from './AuthClient-D8Ul-aGa.mjs';
|
|
3
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 {
|
|
4
|
+
import { H as HttpClient, R as RawTokenResponse, T as TokenResponse } from './TokenResponse-CY1CaU2l.mjs';
|
|
5
|
+
export { a as HttpRequest, b as HttpResponse, c as createFetchHttpClient } from './TokenResponse-CY1CaU2l.mjs';
|
|
6
6
|
|
|
7
7
|
/**
|
|
8
8
|
* Roles emitted by Keycloak realms in the dloizides.com portfolio.
|
|
@@ -315,6 +315,182 @@ declare class BiometricGate {
|
|
|
315
315
|
unlock(): Promise<void>;
|
|
316
316
|
}
|
|
317
317
|
|
|
318
|
+
/** Credentials posted to `POST /bff/login`. */
|
|
319
|
+
interface BffLoginRequest {
|
|
320
|
+
username: string;
|
|
321
|
+
password: string;
|
|
322
|
+
}
|
|
323
|
+
/** Payload for `POST /bff/register` — proxied by the BFF to TenantService. */
|
|
324
|
+
interface BffRegisterRequest {
|
|
325
|
+
firstName: string;
|
|
326
|
+
lastName: string;
|
|
327
|
+
username: string;
|
|
328
|
+
email: string;
|
|
329
|
+
password: string;
|
|
330
|
+
tenantName: string;
|
|
331
|
+
[key: string]: unknown;
|
|
332
|
+
}
|
|
333
|
+
/** Payload for `POST /bff/forgot-password` — proxied to TenantService. */
|
|
334
|
+
interface BffForgotPasswordRequest {
|
|
335
|
+
email: string;
|
|
336
|
+
/** Full URL with a `{token}` placeholder; the backend substitutes the token. */
|
|
337
|
+
resetUrlTemplate?: string;
|
|
338
|
+
[key: string]: unknown;
|
|
339
|
+
}
|
|
340
|
+
/** Payload for `POST /bff/reset-password` — proxied to TenantService. */
|
|
341
|
+
interface BffResetPasswordRequest {
|
|
342
|
+
token: string;
|
|
343
|
+
newPassword: string;
|
|
344
|
+
}
|
|
345
|
+
/**
|
|
346
|
+
* Payload for `POST /bff/otp/request` — the BFF proxies it to TenantService,
|
|
347
|
+
* which generates a short-TTL code and emails it.
|
|
348
|
+
*/
|
|
349
|
+
interface BffOtpRequestRequest {
|
|
350
|
+
/** The email address (or username) the one-time code is sent to. */
|
|
351
|
+
identifier: string;
|
|
352
|
+
}
|
|
353
|
+
/** Payload for `POST /bff/otp/verify` — the BFF exchanges it for a session. */
|
|
354
|
+
interface BffOtpVerifyRequest {
|
|
355
|
+
/** The email / username the code was requested for. */
|
|
356
|
+
username: string;
|
|
357
|
+
/** The one-time code the user entered. */
|
|
358
|
+
otp: string;
|
|
359
|
+
}
|
|
360
|
+
/**
|
|
361
|
+
* Payload for `POST /bff/pin/login` — the BFF exchanges an event-scoped PIN
|
|
362
|
+
* for a session.
|
|
363
|
+
*
|
|
364
|
+
* The `(event, pin)` pair alone identifies the staff member: no `username` /
|
|
365
|
+
* `password` ever leaves the browser. A PIN entered in an event's context
|
|
366
|
+
* grants that staff member their event-scoped role for that event only
|
|
367
|
+
* (the unified-auth plan §4.4 — event-scoped, per-individual PINs).
|
|
368
|
+
*/
|
|
369
|
+
interface BffPinLoginRequest {
|
|
370
|
+
/** The numeric PIN the staff member entered. */
|
|
371
|
+
pin: string;
|
|
372
|
+
/** External id of the event the PIN is scoped to (supplied by the page/route). */
|
|
373
|
+
eventExternalId: string;
|
|
374
|
+
}
|
|
375
|
+
/**
|
|
376
|
+
* The body `POST /bff/otp/request` relays from TenantService.
|
|
377
|
+
*
|
|
378
|
+
* Anti-enumeration: the shape is identical whether or not the identifier is
|
|
379
|
+
* registered. `code` is non-null only outside production (a dev convenience);
|
|
380
|
+
* the UI must never depend on it being present.
|
|
381
|
+
*/
|
|
382
|
+
interface BffOtpRequestResult {
|
|
383
|
+
/** Always `true` on a relayed 200 — the request was accepted. */
|
|
384
|
+
success: boolean;
|
|
385
|
+
/** Seconds until the emitted code expires — drives a countdown in the UI. */
|
|
386
|
+
expiresIn: number;
|
|
387
|
+
/** The code itself, non-production only; `null` (or absent) in production. */
|
|
388
|
+
code: string | null;
|
|
389
|
+
}
|
|
390
|
+
/**
|
|
391
|
+
* The user object returned by `GET /bff/me` and `POST /bff/login`. The BFF
|
|
392
|
+
* returns the sanitised KC claims under a `user` envelope and **never** a
|
|
393
|
+
* token. Kept permissive so server-added claims flow through without a bump.
|
|
394
|
+
*/
|
|
395
|
+
interface BffUser {
|
|
396
|
+
sub?: string;
|
|
397
|
+
email?: string;
|
|
398
|
+
email_verified?: boolean;
|
|
399
|
+
name?: string;
|
|
400
|
+
preferred_username?: string;
|
|
401
|
+
given_name?: string;
|
|
402
|
+
family_name?: string;
|
|
403
|
+
tenantId?: string;
|
|
404
|
+
roles?: string[];
|
|
405
|
+
[key: string]: unknown;
|
|
406
|
+
}
|
|
407
|
+
interface BffAuthClientOptions {
|
|
408
|
+
/** Runtime-agnostic HTTP transport (wrap native `fetch` with `createFetchHttpClient`). */
|
|
409
|
+
http: HttpClient;
|
|
410
|
+
/**
|
|
411
|
+
* BFF origin. Defaults to `''` (same-origin) — the production wiring. An
|
|
412
|
+
* explicit origin is only useful for tests or a non-same-origin BFF.
|
|
413
|
+
*/
|
|
414
|
+
baseUrl?: string;
|
|
415
|
+
}
|
|
416
|
+
/**
|
|
417
|
+
* Same-origin client for a per-app BFF.
|
|
418
|
+
*
|
|
419
|
+
* No token storage, no refresh logic, no realm awareness — the BFF owns all of
|
|
420
|
+
* that server-side. The browser's only auth artefact is the httpOnly cookie.
|
|
421
|
+
*/
|
|
422
|
+
declare class BffAuthClient {
|
|
423
|
+
private readonly http;
|
|
424
|
+
private readonly baseUrl;
|
|
425
|
+
constructor(options: BffAuthClientOptions);
|
|
426
|
+
/**
|
|
427
|
+
* `POST /bff/login` — the BFF does ROPC against Keycloak server-side, stores
|
|
428
|
+
* the tokens in its Redis vault, and sets the httpOnly session cookie.
|
|
429
|
+
* Returns the sanitised user. Throws on a non-2xx response.
|
|
430
|
+
*/
|
|
431
|
+
login(request: BffLoginRequest): Promise<BffUser>;
|
|
432
|
+
/**
|
|
433
|
+
* `POST /bff/logout` — the BFF calls KC end-session, deletes the Redis
|
|
434
|
+
* session, and clears the cookie. Non-fatal: a failed logout still leaves
|
|
435
|
+
* the SPA logged out client-side. Throws only on a non-2xx response.
|
|
436
|
+
*/
|
|
437
|
+
logout(): Promise<void>;
|
|
438
|
+
/**
|
|
439
|
+
* `GET /bff/me` — the live session's sanitised user, or `null` when there is
|
|
440
|
+
* no session (the BFF answers `401`). Used at app load to bootstrap auth
|
|
441
|
+
* state in place of the old token-in-storage check.
|
|
442
|
+
*/
|
|
443
|
+
getCurrentUser(): Promise<BffUser | null>;
|
|
444
|
+
/**
|
|
445
|
+
* `POST /bff/register` — the BFF proxies registration to TenantService and,
|
|
446
|
+
* on success, establishes a session exactly like `login`. Returns the user.
|
|
447
|
+
*/
|
|
448
|
+
register(request: BffRegisterRequest): Promise<BffUser>;
|
|
449
|
+
/**
|
|
450
|
+
* `POST /bff/forgot-password` — proxied to TenantService. The backend
|
|
451
|
+
* returns 200 unconditionally (no email enumeration); anything else throws.
|
|
452
|
+
*/
|
|
453
|
+
forgotPassword(request: BffForgotPasswordRequest): Promise<void>;
|
|
454
|
+
/**
|
|
455
|
+
* `POST /bff/reset-password` — proxied to TenantService. Throws on a non-2xx
|
|
456
|
+
* response (e.g. `400` for an invalid / expired token).
|
|
457
|
+
*/
|
|
458
|
+
resetPassword(request: BffResetPasswordRequest): Promise<void>;
|
|
459
|
+
/**
|
|
460
|
+
* `POST /bff/otp/request` — the BFF proxies to TenantService, which generates
|
|
461
|
+
* a short-TTL code and emails it.
|
|
462
|
+
*
|
|
463
|
+
* The endpoint is anti-enumeration: a `200` is the normal path whether or not
|
|
464
|
+
* the identifier is registered. This method therefore **returns** the relayed
|
|
465
|
+
* `{ success, expiresIn, code }` body (so the UI can show the expiry) rather
|
|
466
|
+
* than treating a 200 as opaque. It still throws on a non-2xx — a `501`
|
|
467
|
+
* (OTP not enabled) or `502` (upstream down) is a real failure to surface.
|
|
468
|
+
*/
|
|
469
|
+
requestOtp(request: BffOtpRequestRequest): Promise<BffOtpRequestResult>;
|
|
470
|
+
/**
|
|
471
|
+
* `POST /bff/otp/verify` — the BFF runs the OTP direct-grant against Keycloak
|
|
472
|
+
* server-side, stores the tokens in its Redis vault, and sets the httpOnly
|
|
473
|
+
* session cookie. Returns the sanitised user, exactly like `login`. Throws on
|
|
474
|
+
* a non-2xx (e.g. `401` for a bad / expired code).
|
|
475
|
+
*/
|
|
476
|
+
verifyOtp(request: BffOtpVerifyRequest): Promise<BffUser>;
|
|
477
|
+
/**
|
|
478
|
+
* `POST /bff/pin/login` — the BFF runs the event-scoped PIN direct-grant
|
|
479
|
+
* against Keycloak server-side (the `(event, pin)` pair resolves to the
|
|
480
|
+
* staff member's KC account + event-scoped role), stores the tokens in its
|
|
481
|
+
* Redis vault, and sets the httpOnly session cookie. Returns the sanitised
|
|
482
|
+
* user, exactly like `login` / `verifyOtp`. Throws on a non-2xx — `401` for
|
|
483
|
+
* a bad / expired / locked-out PIN or an unknown event, `501` when PIN login
|
|
484
|
+
* is not an enabled method for this BFF.
|
|
485
|
+
*/
|
|
486
|
+
pinLogin(request: BffPinLoginRequest): Promise<BffUser>;
|
|
487
|
+
/**
|
|
488
|
+
* Shared POST for every state-changing `/bff/*` call: same-origin, cookie
|
|
489
|
+
* included, `X-BFF-Csrf` header attached. Throws a labelled error on non-2xx.
|
|
490
|
+
*/
|
|
491
|
+
private postState;
|
|
492
|
+
}
|
|
493
|
+
|
|
318
494
|
/**
|
|
319
495
|
* Convert a Keycloak `/userinfo` payload into a flat, app-friendly user object.
|
|
320
496
|
*
|
|
@@ -488,4 +664,4 @@ declare function normalizeTokenResponse(raw: RawTokenResponse): TokenResponse;
|
|
|
488
664
|
*/
|
|
489
665
|
declare function tokenResponseToAuthTokens(response: TokenResponse, now?: number): AuthTokens;
|
|
490
666
|
|
|
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 };
|
|
667
|
+
export { AuthTokens, type AuthorizationCodeBodyInput, type AuthorizationResponseLike, type AuthorizationUrlInput, BffAuthClient, type BffAuthClientOptions, type BffForgotPasswordRequest, type BffLoginRequest, type BffOtpRequestRequest, type BffOtpRequestResult, type BffOtpVerifyRequest, type BffPinLoginRequest, type BffRegisterRequest, type BffResetPasswordRequest, type BffUser, type BiometricFlagStore, BiometricGate, type BiometricGateLike, type BiometricGateOptions, BrowserStorageTokenStorage, type BrowserStorageTokenStorageOptions, CookieTokenStorage, HttpClient, 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,8 +1,8 @@
|
|
|
1
|
-
import { T as TokenStorage,
|
|
2
|
-
export { A as AuthApiClient,
|
|
1
|
+
import { T as TokenStorage, k as AuthTokens } from './AuthClient-Cv7btBX0.js';
|
|
2
|
+
export { A as AuthApiClient, a as AuthApiClientOptions, b as AuthClient, c as AuthClientCollaborators, d as AuthClientConfig, e as AuthClientFromIssuerInput, f as AuthEventEmitter, g as AuthEventListener, h as AuthEventName, i as AuthEventUnsubscribe, j 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, R as RawAuthLoginResponse, o as RefreshFn, p as RefreshInterceptor, q as RefreshInterceptorOptions, r as ResetPasswordRequest } from './AuthClient-Cv7btBX0.js';
|
|
3
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 {
|
|
4
|
+
import { H as HttpClient, R as RawTokenResponse, T as TokenResponse } from './TokenResponse-CY1CaU2l.js';
|
|
5
|
+
export { a as HttpRequest, b as HttpResponse, c as createFetchHttpClient } from './TokenResponse-CY1CaU2l.js';
|
|
6
6
|
|
|
7
7
|
/**
|
|
8
8
|
* Roles emitted by Keycloak realms in the dloizides.com portfolio.
|
|
@@ -315,6 +315,182 @@ declare class BiometricGate {
|
|
|
315
315
|
unlock(): Promise<void>;
|
|
316
316
|
}
|
|
317
317
|
|
|
318
|
+
/** Credentials posted to `POST /bff/login`. */
|
|
319
|
+
interface BffLoginRequest {
|
|
320
|
+
username: string;
|
|
321
|
+
password: string;
|
|
322
|
+
}
|
|
323
|
+
/** Payload for `POST /bff/register` — proxied by the BFF to TenantService. */
|
|
324
|
+
interface BffRegisterRequest {
|
|
325
|
+
firstName: string;
|
|
326
|
+
lastName: string;
|
|
327
|
+
username: string;
|
|
328
|
+
email: string;
|
|
329
|
+
password: string;
|
|
330
|
+
tenantName: string;
|
|
331
|
+
[key: string]: unknown;
|
|
332
|
+
}
|
|
333
|
+
/** Payload for `POST /bff/forgot-password` — proxied to TenantService. */
|
|
334
|
+
interface BffForgotPasswordRequest {
|
|
335
|
+
email: string;
|
|
336
|
+
/** Full URL with a `{token}` placeholder; the backend substitutes the token. */
|
|
337
|
+
resetUrlTemplate?: string;
|
|
338
|
+
[key: string]: unknown;
|
|
339
|
+
}
|
|
340
|
+
/** Payload for `POST /bff/reset-password` — proxied to TenantService. */
|
|
341
|
+
interface BffResetPasswordRequest {
|
|
342
|
+
token: string;
|
|
343
|
+
newPassword: string;
|
|
344
|
+
}
|
|
345
|
+
/**
|
|
346
|
+
* Payload for `POST /bff/otp/request` — the BFF proxies it to TenantService,
|
|
347
|
+
* which generates a short-TTL code and emails it.
|
|
348
|
+
*/
|
|
349
|
+
interface BffOtpRequestRequest {
|
|
350
|
+
/** The email address (or username) the one-time code is sent to. */
|
|
351
|
+
identifier: string;
|
|
352
|
+
}
|
|
353
|
+
/** Payload for `POST /bff/otp/verify` — the BFF exchanges it for a session. */
|
|
354
|
+
interface BffOtpVerifyRequest {
|
|
355
|
+
/** The email / username the code was requested for. */
|
|
356
|
+
username: string;
|
|
357
|
+
/** The one-time code the user entered. */
|
|
358
|
+
otp: string;
|
|
359
|
+
}
|
|
360
|
+
/**
|
|
361
|
+
* Payload for `POST /bff/pin/login` — the BFF exchanges an event-scoped PIN
|
|
362
|
+
* for a session.
|
|
363
|
+
*
|
|
364
|
+
* The `(event, pin)` pair alone identifies the staff member: no `username` /
|
|
365
|
+
* `password` ever leaves the browser. A PIN entered in an event's context
|
|
366
|
+
* grants that staff member their event-scoped role for that event only
|
|
367
|
+
* (the unified-auth plan §4.4 — event-scoped, per-individual PINs).
|
|
368
|
+
*/
|
|
369
|
+
interface BffPinLoginRequest {
|
|
370
|
+
/** The numeric PIN the staff member entered. */
|
|
371
|
+
pin: string;
|
|
372
|
+
/** External id of the event the PIN is scoped to (supplied by the page/route). */
|
|
373
|
+
eventExternalId: string;
|
|
374
|
+
}
|
|
375
|
+
/**
|
|
376
|
+
* The body `POST /bff/otp/request` relays from TenantService.
|
|
377
|
+
*
|
|
378
|
+
* Anti-enumeration: the shape is identical whether or not the identifier is
|
|
379
|
+
* registered. `code` is non-null only outside production (a dev convenience);
|
|
380
|
+
* the UI must never depend on it being present.
|
|
381
|
+
*/
|
|
382
|
+
interface BffOtpRequestResult {
|
|
383
|
+
/** Always `true` on a relayed 200 — the request was accepted. */
|
|
384
|
+
success: boolean;
|
|
385
|
+
/** Seconds until the emitted code expires — drives a countdown in the UI. */
|
|
386
|
+
expiresIn: number;
|
|
387
|
+
/** The code itself, non-production only; `null` (or absent) in production. */
|
|
388
|
+
code: string | null;
|
|
389
|
+
}
|
|
390
|
+
/**
|
|
391
|
+
* The user object returned by `GET /bff/me` and `POST /bff/login`. The BFF
|
|
392
|
+
* returns the sanitised KC claims under a `user` envelope and **never** a
|
|
393
|
+
* token. Kept permissive so server-added claims flow through without a bump.
|
|
394
|
+
*/
|
|
395
|
+
interface BffUser {
|
|
396
|
+
sub?: string;
|
|
397
|
+
email?: string;
|
|
398
|
+
email_verified?: boolean;
|
|
399
|
+
name?: string;
|
|
400
|
+
preferred_username?: string;
|
|
401
|
+
given_name?: string;
|
|
402
|
+
family_name?: string;
|
|
403
|
+
tenantId?: string;
|
|
404
|
+
roles?: string[];
|
|
405
|
+
[key: string]: unknown;
|
|
406
|
+
}
|
|
407
|
+
interface BffAuthClientOptions {
|
|
408
|
+
/** Runtime-agnostic HTTP transport (wrap native `fetch` with `createFetchHttpClient`). */
|
|
409
|
+
http: HttpClient;
|
|
410
|
+
/**
|
|
411
|
+
* BFF origin. Defaults to `''` (same-origin) — the production wiring. An
|
|
412
|
+
* explicit origin is only useful for tests or a non-same-origin BFF.
|
|
413
|
+
*/
|
|
414
|
+
baseUrl?: string;
|
|
415
|
+
}
|
|
416
|
+
/**
|
|
417
|
+
* Same-origin client for a per-app BFF.
|
|
418
|
+
*
|
|
419
|
+
* No token storage, no refresh logic, no realm awareness — the BFF owns all of
|
|
420
|
+
* that server-side. The browser's only auth artefact is the httpOnly cookie.
|
|
421
|
+
*/
|
|
422
|
+
declare class BffAuthClient {
|
|
423
|
+
private readonly http;
|
|
424
|
+
private readonly baseUrl;
|
|
425
|
+
constructor(options: BffAuthClientOptions);
|
|
426
|
+
/**
|
|
427
|
+
* `POST /bff/login` — the BFF does ROPC against Keycloak server-side, stores
|
|
428
|
+
* the tokens in its Redis vault, and sets the httpOnly session cookie.
|
|
429
|
+
* Returns the sanitised user. Throws on a non-2xx response.
|
|
430
|
+
*/
|
|
431
|
+
login(request: BffLoginRequest): Promise<BffUser>;
|
|
432
|
+
/**
|
|
433
|
+
* `POST /bff/logout` — the BFF calls KC end-session, deletes the Redis
|
|
434
|
+
* session, and clears the cookie. Non-fatal: a failed logout still leaves
|
|
435
|
+
* the SPA logged out client-side. Throws only on a non-2xx response.
|
|
436
|
+
*/
|
|
437
|
+
logout(): Promise<void>;
|
|
438
|
+
/**
|
|
439
|
+
* `GET /bff/me` — the live session's sanitised user, or `null` when there is
|
|
440
|
+
* no session (the BFF answers `401`). Used at app load to bootstrap auth
|
|
441
|
+
* state in place of the old token-in-storage check.
|
|
442
|
+
*/
|
|
443
|
+
getCurrentUser(): Promise<BffUser | null>;
|
|
444
|
+
/**
|
|
445
|
+
* `POST /bff/register` — the BFF proxies registration to TenantService and,
|
|
446
|
+
* on success, establishes a session exactly like `login`. Returns the user.
|
|
447
|
+
*/
|
|
448
|
+
register(request: BffRegisterRequest): Promise<BffUser>;
|
|
449
|
+
/**
|
|
450
|
+
* `POST /bff/forgot-password` — proxied to TenantService. The backend
|
|
451
|
+
* returns 200 unconditionally (no email enumeration); anything else throws.
|
|
452
|
+
*/
|
|
453
|
+
forgotPassword(request: BffForgotPasswordRequest): Promise<void>;
|
|
454
|
+
/**
|
|
455
|
+
* `POST /bff/reset-password` — proxied to TenantService. Throws on a non-2xx
|
|
456
|
+
* response (e.g. `400` for an invalid / expired token).
|
|
457
|
+
*/
|
|
458
|
+
resetPassword(request: BffResetPasswordRequest): Promise<void>;
|
|
459
|
+
/**
|
|
460
|
+
* `POST /bff/otp/request` — the BFF proxies to TenantService, which generates
|
|
461
|
+
* a short-TTL code and emails it.
|
|
462
|
+
*
|
|
463
|
+
* The endpoint is anti-enumeration: a `200` is the normal path whether or not
|
|
464
|
+
* the identifier is registered. This method therefore **returns** the relayed
|
|
465
|
+
* `{ success, expiresIn, code }` body (so the UI can show the expiry) rather
|
|
466
|
+
* than treating a 200 as opaque. It still throws on a non-2xx — a `501`
|
|
467
|
+
* (OTP not enabled) or `502` (upstream down) is a real failure to surface.
|
|
468
|
+
*/
|
|
469
|
+
requestOtp(request: BffOtpRequestRequest): Promise<BffOtpRequestResult>;
|
|
470
|
+
/**
|
|
471
|
+
* `POST /bff/otp/verify` — the BFF runs the OTP direct-grant against Keycloak
|
|
472
|
+
* server-side, stores the tokens in its Redis vault, and sets the httpOnly
|
|
473
|
+
* session cookie. Returns the sanitised user, exactly like `login`. Throws on
|
|
474
|
+
* a non-2xx (e.g. `401` for a bad / expired code).
|
|
475
|
+
*/
|
|
476
|
+
verifyOtp(request: BffOtpVerifyRequest): Promise<BffUser>;
|
|
477
|
+
/**
|
|
478
|
+
* `POST /bff/pin/login` — the BFF runs the event-scoped PIN direct-grant
|
|
479
|
+
* against Keycloak server-side (the `(event, pin)` pair resolves to the
|
|
480
|
+
* staff member's KC account + event-scoped role), stores the tokens in its
|
|
481
|
+
* Redis vault, and sets the httpOnly session cookie. Returns the sanitised
|
|
482
|
+
* user, exactly like `login` / `verifyOtp`. Throws on a non-2xx — `401` for
|
|
483
|
+
* a bad / expired / locked-out PIN or an unknown event, `501` when PIN login
|
|
484
|
+
* is not an enabled method for this BFF.
|
|
485
|
+
*/
|
|
486
|
+
pinLogin(request: BffPinLoginRequest): Promise<BffUser>;
|
|
487
|
+
/**
|
|
488
|
+
* Shared POST for every state-changing `/bff/*` call: same-origin, cookie
|
|
489
|
+
* included, `X-BFF-Csrf` header attached. Throws a labelled error on non-2xx.
|
|
490
|
+
*/
|
|
491
|
+
private postState;
|
|
492
|
+
}
|
|
493
|
+
|
|
318
494
|
/**
|
|
319
495
|
* Convert a Keycloak `/userinfo` payload into a flat, app-friendly user object.
|
|
320
496
|
*
|
|
@@ -488,4 +664,4 @@ declare function normalizeTokenResponse(raw: RawTokenResponse): TokenResponse;
|
|
|
488
664
|
*/
|
|
489
665
|
declare function tokenResponseToAuthTokens(response: TokenResponse, now?: number): AuthTokens;
|
|
490
666
|
|
|
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 };
|
|
667
|
+
export { AuthTokens, type AuthorizationCodeBodyInput, type AuthorizationResponseLike, type AuthorizationUrlInput, BffAuthClient, type BffAuthClientOptions, type BffForgotPasswordRequest, type BffLoginRequest, type BffOtpRequestRequest, type BffOtpRequestResult, type BffOtpVerifyRequest, type BffPinLoginRequest, type BffRegisterRequest, type BffResetPasswordRequest, type BffUser, type BiometricFlagStore, BiometricGate, type BiometricGateLike, type BiometricGateOptions, BrowserStorageTokenStorage, type BrowserStorageTokenStorageOptions, CookieTokenStorage, HttpClient, 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 };
|