@dloizides/auth-web 1.9.0 → 1.10.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 +53 -0
- package/dist/index.d.mts +92 -25
- package/dist/index.d.ts +92 -25
- package/dist/index.js +65 -10
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +65 -11
- package/dist/index.mjs.map +1 -1
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,58 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 1.10.0 (2026-07-17)
|
|
4
|
+
|
|
5
|
+
Additive release adding the shared **logout sequencer**. Purely additive — every
|
|
6
|
+
1.9.x export is unchanged, no component behaviour changes, and apps that do not
|
|
7
|
+
import `performBffLogout` are byte-identical.
|
|
8
|
+
|
|
9
|
+
### Added
|
|
10
|
+
|
|
11
|
+
- **`performBffLogout({ client, onClearSession?, onRedirect?, onError?, navigateToIdp? })`**
|
|
12
|
+
— the shared logout sequence, extracted because all six consuming apps
|
|
13
|
+
hand-rolled it in their own `AuthProvider` and the orderings disagreed. Runs:
|
|
14
|
+
1. `onClearSession()` — local state first, so the UI reflects the sign-out
|
|
15
|
+
immediately.
|
|
16
|
+
2. `await client.logout({ redirect: false })` — lets the `POST /bff/logout`
|
|
17
|
+
SETTLE, and takes the IdP logout URL rather than letting the client navigate
|
|
18
|
+
mid-sequence.
|
|
19
|
+
3. Navigates exactly once, last: to the IdP logout URL when the BFF returned
|
|
20
|
+
one (ending the IdP browser session), otherwise `onRedirect()`. When it
|
|
21
|
+
navigates to the IdP it deliberately does NOT also call `onRedirect` — two
|
|
22
|
+
competing navigations would race, and the IdP round-trip already returns the
|
|
23
|
+
user to the app.
|
|
24
|
+
|
|
25
|
+
Never rejects; always navigates, even when the BFF logout fails (a down BFF
|
|
26
|
+
must not trap the user on a page they asked to leave).
|
|
27
|
+
- **`BffLogoutClient`** / **`PerformBffLogoutOptions`** types.
|
|
28
|
+
|
|
29
|
+
### Why
|
|
30
|
+
|
|
31
|
+
`zygos-web` and `agora-web` navigated FIRST and called the BFF second:
|
|
32
|
+
|
|
33
|
+
```ts
|
|
34
|
+
redirectTo('/(auth)/login'); // → window.location.replace() → document unload
|
|
35
|
+
await bffAuthClient.logout(); // races the unload — may never be sent
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
That is wrong twice over:
|
|
39
|
+
|
|
40
|
+
1. **The BFF call can be cancelled.** A document navigation kills in-flight
|
|
41
|
+
fetches, so `POST /bff/logout` may never reach the server: the SPA looks
|
|
42
|
+
logged out while the httpOnly session cookie stays alive. The `catch` logged
|
|
43
|
+
it "non-fatal", so the defect was silent.
|
|
44
|
+
2. **The IdP session survives.** `BffAuthClient.logout()` ends the identity
|
|
45
|
+
provider's browser session with a top-level navigation to its RP-initiated
|
|
46
|
+
logout URL (only a real navigation carries the IdP's own cookie — a
|
|
47
|
+
back-channel POST cannot clear it). An app that navigates to its own login
|
|
48
|
+
route first pre-empts that navigation, so the IdP still considers the user
|
|
49
|
+
signed in and the next authorize round-trip silently re-authenticates them —
|
|
50
|
+
the "sign-out that signs you back in" bug the client's own docs warn about.
|
|
51
|
+
|
|
52
|
+
Synthetic tests that stub the client never reproduce either failure (there is no
|
|
53
|
+
real navigation to cancel the request), which is why they survived. The helper
|
|
54
|
+
owns the sequence so neither can be reintroduced per-app.
|
|
55
|
+
|
|
3
56
|
## 1.8.0 (2026-07-09)
|
|
4
57
|
|
|
5
58
|
Additive release for the Move 2b passkey in-app rebuild — the passkey ceremony
|
package/dist/index.d.mts
CHANGED
|
@@ -1694,30 +1694,6 @@ declare const enum PasskeyCeremonyStatus {
|
|
|
1694
1694
|
Error = "error"
|
|
1695
1695
|
}
|
|
1696
1696
|
|
|
1697
|
-
/**
|
|
1698
|
-
* Navigation helpers for the passkey (WebAuthn) BFF endpoints.
|
|
1699
|
-
*
|
|
1700
|
-
* Unlike the device-PIN client (which is plain `fetch`), the passkey login and
|
|
1701
|
-
* registration ceremonies are NOT fetches — they are full-page BROWSER
|
|
1702
|
-
* NAVIGATIONS. The BFF (`Bff.AspNetCore` 1.3.x) drives the WebAuthn ceremony
|
|
1703
|
-
* through Keycloak's hosted pages, then redirects the browser back:
|
|
1704
|
-
* - login: `/bff/passkey/login?returnUrl=<rel>` → on success the browser
|
|
1705
|
-
* lands on `returnUrl` with the session cookie already set;
|
|
1706
|
-
* - registration: `/bff/passkey/register?returnUrl=<rel>` → Keycloak re-auths
|
|
1707
|
-
* the user (password) then runs the credential-creation ceremony, returning
|
|
1708
|
-
* the browser to `returnUrl?passkey=registered`;
|
|
1709
|
-
* - failure / cancel: the BFF redirects to `<login>?passkeyError=cancelled` or
|
|
1710
|
-
* `<login>?passkeyError=failed`.
|
|
1711
|
-
*
|
|
1712
|
-
* react-query-FREE by construction: there is NO fetch here at all — every
|
|
1713
|
-
* function is a pure `window.location` read or `window.location.assign`. The
|
|
1714
|
-
* login route group has no QueryClient provider, so the passkey login button
|
|
1715
|
-
* (which lives there) MUST avoid any react-query primitive; navigation satisfies
|
|
1716
|
-
* that trivially.
|
|
1717
|
-
*
|
|
1718
|
-
* All reads are SSR-safe: when `window` is undefined (server render / native)
|
|
1719
|
-
* they return a benign default rather than throwing.
|
|
1720
|
-
*/
|
|
1721
1697
|
/** The recognised passkey error codes the BFF sends back via `?passkeyError=`. */
|
|
1722
1698
|
type PasskeyErrorCode = 'cancelled' | 'failed';
|
|
1723
1699
|
/**
|
|
@@ -1949,6 +1925,97 @@ declare function resolvePostLoginRoute(user: BffUser, table: RoleRouteTable): st
|
|
|
1949
1925
|
*/
|
|
1950
1926
|
declare function resolveAccessibleRoutes(user: BffUser, table: RoleRouteTable): RoleRoute[];
|
|
1951
1927
|
|
|
1928
|
+
/**
|
|
1929
|
+
* `performBffLogout` — the shared logout sequencer.
|
|
1930
|
+
*
|
|
1931
|
+
* Every app hand-rolled its own logout ordering inside its `AuthProvider`, and
|
|
1932
|
+
* the orderings disagreed. Two of them (zygos-web, agora-web) navigated FIRST
|
|
1933
|
+
* and called the BFF second:
|
|
1934
|
+
*
|
|
1935
|
+
* ```ts
|
|
1936
|
+
* redirectTo('/(auth)/login'); // window.location.replace() → document unload
|
|
1937
|
+
* await bffAuthClient.logout(); // races the unload — may never be sent
|
|
1938
|
+
* ```
|
|
1939
|
+
*
|
|
1940
|
+
* That is wrong twice over:
|
|
1941
|
+
*
|
|
1942
|
+
* 1. **The BFF call can be cancelled.** A document navigation kills in-flight
|
|
1943
|
+
* fetches, so `POST /bff/logout` may never reach the server: the SPA looks
|
|
1944
|
+
* logged out while the httpOnly session cookie stays ALIVE. The `catch`
|
|
1945
|
+
* logged it "non-fatal", so the defect was silent.
|
|
1946
|
+
* 2. **The IdP session survives.** `BffAuthClient.logout()` ends the *identity
|
|
1947
|
+
* provider's* browser session by doing a top-level navigation to the IdP's
|
|
1948
|
+
* RP-initiated logout URL (only a real navigation carries the IdP's own
|
|
1949
|
+
* cookie — a back-channel POST cannot clear it). An app that navigates to
|
|
1950
|
+
* its own login route first pre-empts that navigation, so the IdP still
|
|
1951
|
+
* considers the user signed in and the next authorize round-trip silently
|
|
1952
|
+
* re-authenticates them. That is the "sign-out that signs you back in" bug
|
|
1953
|
+
* the client's own docs warn about.
|
|
1954
|
+
*
|
|
1955
|
+
* This helper owns the whole sequence so neither can be reintroduced per-app:
|
|
1956
|
+
*
|
|
1957
|
+
* 1. `onClearSession()` — drop local state immediately so the UI reflects the
|
|
1958
|
+
* sign-out right away (perceived performance; no spinner needed).
|
|
1959
|
+
* 2. `await client.logout({ redirect: false })` — let the network call SETTLE,
|
|
1960
|
+
* and take the IdP logout URL rather than letting the client navigate mid-
|
|
1961
|
+
* sequence. Errors are captured, never rethrown.
|
|
1962
|
+
* 3. Navigate LAST, exactly once, when nothing is in flight to cancel:
|
|
1963
|
+
* - an IdP logout URL → a top-level navigation to the IdP, which ends that
|
|
1964
|
+
* session and bounces the user back. `onRedirect` is deliberately NOT
|
|
1965
|
+
* called: two competing navigations would race, and the IdP round-trip
|
|
1966
|
+
* already returns the user to the app.
|
|
1967
|
+
* - otherwise (ROPC / OTP / device-PIN logins never had an IdP cookie, so
|
|
1968
|
+
* the URL is `null`) → `onRedirect()`, the app's own login route.
|
|
1969
|
+
*
|
|
1970
|
+
* Step 3 runs even when step 2 rejects: a BFF that is down must not trap the
|
|
1971
|
+
* user on a page they asked to leave. The local session is already gone, so the
|
|
1972
|
+
* client-side sign-out holds regardless.
|
|
1973
|
+
*
|
|
1974
|
+
* Headless and framework-free: it takes callbacks, so an app can pair it with
|
|
1975
|
+
* Redux, a context, expo-router, or `window.location` without this package
|
|
1976
|
+
* knowing about any of them.
|
|
1977
|
+
*/
|
|
1978
|
+
/**
|
|
1979
|
+
* The only part of a `BffAuthClient` this helper needs. Structural, so it is
|
|
1980
|
+
* trivially fakeable in tests and does not couple to the full client surface.
|
|
1981
|
+
*/
|
|
1982
|
+
interface BffLogoutClient {
|
|
1983
|
+
/**
|
|
1984
|
+
* `POST /bff/logout` — ends the server-side session. With `redirect: false`
|
|
1985
|
+
* it returns the IdP's RP-initiated logout URL (or `null` when the session
|
|
1986
|
+
* never involved an IdP browser cookie) instead of navigating there itself.
|
|
1987
|
+
*/
|
|
1988
|
+
logout: (options?: {
|
|
1989
|
+
redirect?: boolean;
|
|
1990
|
+
}) => Promise<string | null>;
|
|
1991
|
+
}
|
|
1992
|
+
/** Callbacks + client for {@link performBffLogout}. */
|
|
1993
|
+
interface PerformBffLogoutOptions {
|
|
1994
|
+
/** The BFF auth client whose `logout()` ends the server-side session. */
|
|
1995
|
+
client: BffLogoutClient;
|
|
1996
|
+
/** Drop local session state. Runs BEFORE the network call. Optional. */
|
|
1997
|
+
onClearSession?: () => void;
|
|
1998
|
+
/**
|
|
1999
|
+
* Navigate to the app's logged-out route. Runs only AFTER the network call
|
|
2000
|
+
* settles, and only when there is no IdP logout URL to honour. Optional.
|
|
2001
|
+
*/
|
|
2002
|
+
onRedirect?: () => void;
|
|
2003
|
+
/** Observe a failed logout step (e.g. to log it). Never rethrown. Optional. */
|
|
2004
|
+
onError?: (error: Error) => void;
|
|
2005
|
+
/**
|
|
2006
|
+
* Test seam: perform the top-level navigation to the IdP logout URL. Defaults
|
|
2007
|
+
* to `window.location.assign`. Must be a real navigation — a `fetch` here
|
|
2008
|
+
* would not carry the IdP cookie and would silently fail to end the session.
|
|
2009
|
+
*/
|
|
2010
|
+
navigateToIdp?: (url: string) => void;
|
|
2011
|
+
}
|
|
2012
|
+
/**
|
|
2013
|
+
* End the session: clear locally, await the BFF, then navigate exactly once.
|
|
2014
|
+
*
|
|
2015
|
+
* Never rejects — callers may `void` it safely.
|
|
2016
|
+
*/
|
|
2017
|
+
declare function performBffLogout(options: Readonly<PerformBffLogoutOptions>): Promise<void>;
|
|
2018
|
+
|
|
1952
2019
|
/**
|
|
1953
2020
|
* The discrete ways a password can fail the shared client-side policy.
|
|
1954
2021
|
*
|
|
@@ -1994,4 +2061,4 @@ declare function validatePasswordPolicy(password: string): PasswordPolicyError[]
|
|
|
1994
2061
|
/** `true` when the password satisfies every policy rule. */
|
|
1995
2062
|
declare function isPasswordValid(password: string): boolean;
|
|
1996
2063
|
|
|
1997
|
-
export { AuthScreen, type AuthScreenProps, AuthTestIds, type AuthTheme, type AuthThemeColors, AuthThemeProvider, type AuthThemeProviderProps, type AuthThemeRadii, type AuthThemeSpacing, type AuthThemeTypography, BffAuthStatus, type BffDeviceState, type BffLoginConfig, type CreateBffAuthClientOptions, DEFAULT_AUTH_CARD_MAX_WIDTH, DEFAULT_DEVICE_PIN_ENROLL_LABELS, DEFAULT_DEVICE_PIN_SETTINGS_LABELS, DEFAULT_DEVICE_PIN_UNLOCK_LABELS, DEFAULT_FORGOT_PASSWORD_FIELDS_LABELS, DEFAULT_FORGOT_PASSWORD_LABELS, DEFAULT_LOGIN_LABELS, DEFAULT_OTP_LABELS, DEFAULT_PASSKEY_LOGIN_LABELS, DEFAULT_PASSKEY_SETTINGS_LABELS, DEFAULT_PIN_LABELS, DEFAULT_PREFERRED_METHOD_HINT_LABELS, DEFAULT_PREFERRED_METHOD_SETTINGS_LABELS, DEFAULT_RESET_PASSWORD_LABELS, DEVICE_PIN_ALLOWED_DIGITS, DEVICE_PIN_DEFAULT_DIGITS, type DevicePinCapableClient, type DevicePinDisableCapableClient, type DevicePinEnrollCapableClient, DevicePinEnrollErrorKey, DevicePinEnrollForm, type DevicePinEnrollFormProps, type DevicePinEnrollLabels, type DevicePinEnrollResult, DevicePinErrorKey, DevicePinInput, type DevicePinInputProps, DevicePinLengthPicker, type DevicePinLengthPickerProps, DevicePinOffer, type DevicePinOfferProps, DevicePinSettingsCard, type DevicePinSettingsCardProps, type DevicePinSettingsLabels, type DevicePinUnlockCapableClient, type DevicePinUnlockLabels, type DevicePinUnlockResult, DevicePinUnlockScreen, type DevicePinUnlockScreenProps, type DevicePinUnlockedUser, ForgotPasswordFields, type ForgotPasswordFieldsLabels, type ForgotPasswordFieldsProps, ForgotPasswordForm, type ForgotPasswordFormLabels, type ForgotPasswordFormProps, type LoginConfigCapableClient, LoginForm, type LoginFormLabels, type LoginFormProps, OtpForm, type OtpFormLabels, type OtpFormProps, OtpLoginStep, PASSWORD_MAX_LENGTH, PASSWORD_MIN_LENGTH, PasskeyCeremonyMode, PasskeyCeremonyStatus, type PasskeyErrorCode, PasskeyLoginButton, type PasskeyLoginButtonProps, type PasskeyLoginLabels, PasskeySettingsCard, type PasskeySettingsCardProps, type PasskeySettingsLabels, PasswordPolicyError, PinForm, type PinFormLabels, type PinFormProps, type PreferencesClientOptions, type PreferredMethodClient, PreferredMethodHint, type PreferredMethodHintLabels, type PreferredMethodHintProps, PreferredMethodSettingsCard, type PreferredMethodSettingsCardProps, type PreferredMethodSettingsLabels, ResetPasswordError, ResetPasswordForm, type ResetPasswordFormLabels, type ResetPasswordFormProps, type RoleRoute, type RoleRouteTable, type UseBffAuthOptions, type UseBffAuthResult, type UseBffForgotPasswordOptions, type UseBffLoginConfigResult, type UseBffResetPasswordOptions, type UseDevicePinDisableArgs, type UseDevicePinDisableResult, type UseDevicePinEnrollArgs, type UseDevicePinEnrollResult, type UseDevicePinUnlockArgs, type UseDevicePinUnlockResult, type UseForgotPasswordSubmitArgs, type UseForgotPasswordSubmitResult, type UseOtpLoginOptions, type UseOtpLoginResult, type UsePasskeyCeremonyOptions, type UsePasskeyCeremonyResult, type UsePinLoginOptions, type UsePinLoginResult, type UsePreferredMethodSettingArgs, type UsePreferredMethodSettingResult, type UseResetPasswordFormArgs, type UseResetPasswordFormResult, cachePreferredMethod, clearCachedPreferredMethod, collectUserRoles, createBffAuthClient, createPreferencesClient, defaultAuthTheme, isAllowedPinDigits, isPasswordValid, isValidForgotPasswordEmail, readCachedPreferredMethod, readPasskeyError, readPasskeyRegistered, resolveAccessibleRoutes, resolvePostLoginRoute, startPasskeyLogin, startPasskeyRegistration, syncPreferredMethodFromServer, useAuthTheme, useBffAuth, useBffForgotPassword, useBffLoginConfig, useBffResetPassword, useDevicePinDisable, useDevicePinEnroll, useDevicePinUnlock, useForgotPasswordSubmit, useOtpLogin, usePasskeyCeremony, usePinLogin, usePreferredMethodSetting, useResetPasswordForm, validatePasswordPolicy, withTestIdPrefix };
|
|
2064
|
+
export { AuthScreen, type AuthScreenProps, AuthTestIds, type AuthTheme, type AuthThemeColors, AuthThemeProvider, type AuthThemeProviderProps, type AuthThemeRadii, type AuthThemeSpacing, type AuthThemeTypography, BffAuthStatus, type BffDeviceState, type BffLoginConfig, type BffLogoutClient, type CreateBffAuthClientOptions, DEFAULT_AUTH_CARD_MAX_WIDTH, DEFAULT_DEVICE_PIN_ENROLL_LABELS, DEFAULT_DEVICE_PIN_SETTINGS_LABELS, DEFAULT_DEVICE_PIN_UNLOCK_LABELS, DEFAULT_FORGOT_PASSWORD_FIELDS_LABELS, DEFAULT_FORGOT_PASSWORD_LABELS, DEFAULT_LOGIN_LABELS, DEFAULT_OTP_LABELS, DEFAULT_PASSKEY_LOGIN_LABELS, DEFAULT_PASSKEY_SETTINGS_LABELS, DEFAULT_PIN_LABELS, DEFAULT_PREFERRED_METHOD_HINT_LABELS, DEFAULT_PREFERRED_METHOD_SETTINGS_LABELS, DEFAULT_RESET_PASSWORD_LABELS, DEVICE_PIN_ALLOWED_DIGITS, DEVICE_PIN_DEFAULT_DIGITS, type DevicePinCapableClient, type DevicePinDisableCapableClient, type DevicePinEnrollCapableClient, DevicePinEnrollErrorKey, DevicePinEnrollForm, type DevicePinEnrollFormProps, type DevicePinEnrollLabels, type DevicePinEnrollResult, DevicePinErrorKey, DevicePinInput, type DevicePinInputProps, DevicePinLengthPicker, type DevicePinLengthPickerProps, DevicePinOffer, type DevicePinOfferProps, DevicePinSettingsCard, type DevicePinSettingsCardProps, type DevicePinSettingsLabels, type DevicePinUnlockCapableClient, type DevicePinUnlockLabels, type DevicePinUnlockResult, DevicePinUnlockScreen, type DevicePinUnlockScreenProps, type DevicePinUnlockedUser, ForgotPasswordFields, type ForgotPasswordFieldsLabels, type ForgotPasswordFieldsProps, ForgotPasswordForm, type ForgotPasswordFormLabels, type ForgotPasswordFormProps, type LoginConfigCapableClient, LoginForm, type LoginFormLabels, type LoginFormProps, OtpForm, type OtpFormLabels, type OtpFormProps, OtpLoginStep, PASSWORD_MAX_LENGTH, PASSWORD_MIN_LENGTH, PasskeyCeremonyMode, PasskeyCeremonyStatus, type PasskeyErrorCode, PasskeyLoginButton, type PasskeyLoginButtonProps, type PasskeyLoginLabels, PasskeySettingsCard, type PasskeySettingsCardProps, type PasskeySettingsLabels, PasswordPolicyError, type PerformBffLogoutOptions, PinForm, type PinFormLabels, type PinFormProps, type PreferencesClientOptions, type PreferredMethodClient, PreferredMethodHint, type PreferredMethodHintLabels, type PreferredMethodHintProps, PreferredMethodSettingsCard, type PreferredMethodSettingsCardProps, type PreferredMethodSettingsLabels, ResetPasswordError, ResetPasswordForm, type ResetPasswordFormLabels, type ResetPasswordFormProps, type RoleRoute, type RoleRouteTable, type UseBffAuthOptions, type UseBffAuthResult, type UseBffForgotPasswordOptions, type UseBffLoginConfigResult, type UseBffResetPasswordOptions, type UseDevicePinDisableArgs, type UseDevicePinDisableResult, type UseDevicePinEnrollArgs, type UseDevicePinEnrollResult, type UseDevicePinUnlockArgs, type UseDevicePinUnlockResult, type UseForgotPasswordSubmitArgs, type UseForgotPasswordSubmitResult, type UseOtpLoginOptions, type UseOtpLoginResult, type UsePasskeyCeremonyOptions, type UsePasskeyCeremonyResult, type UsePinLoginOptions, type UsePinLoginResult, type UsePreferredMethodSettingArgs, type UsePreferredMethodSettingResult, type UseResetPasswordFormArgs, type UseResetPasswordFormResult, cachePreferredMethod, clearCachedPreferredMethod, collectUserRoles, createBffAuthClient, createPreferencesClient, defaultAuthTheme, isAllowedPinDigits, isPasswordValid, isValidForgotPasswordEmail, performBffLogout, readCachedPreferredMethod, readPasskeyError, readPasskeyRegistered, resolveAccessibleRoutes, resolvePostLoginRoute, startPasskeyLogin, startPasskeyRegistration, syncPreferredMethodFromServer, useAuthTheme, useBffAuth, useBffForgotPassword, useBffLoginConfig, useBffResetPassword, useDevicePinDisable, useDevicePinEnroll, useDevicePinUnlock, useForgotPasswordSubmit, useOtpLogin, usePasskeyCeremony, usePinLogin, usePreferredMethodSetting, useResetPasswordForm, validatePasswordPolicy, withTestIdPrefix };
|
package/dist/index.d.ts
CHANGED
|
@@ -1694,30 +1694,6 @@ declare const enum PasskeyCeremonyStatus {
|
|
|
1694
1694
|
Error = "error"
|
|
1695
1695
|
}
|
|
1696
1696
|
|
|
1697
|
-
/**
|
|
1698
|
-
* Navigation helpers for the passkey (WebAuthn) BFF endpoints.
|
|
1699
|
-
*
|
|
1700
|
-
* Unlike the device-PIN client (which is plain `fetch`), the passkey login and
|
|
1701
|
-
* registration ceremonies are NOT fetches — they are full-page BROWSER
|
|
1702
|
-
* NAVIGATIONS. The BFF (`Bff.AspNetCore` 1.3.x) drives the WebAuthn ceremony
|
|
1703
|
-
* through Keycloak's hosted pages, then redirects the browser back:
|
|
1704
|
-
* - login: `/bff/passkey/login?returnUrl=<rel>` → on success the browser
|
|
1705
|
-
* lands on `returnUrl` with the session cookie already set;
|
|
1706
|
-
* - registration: `/bff/passkey/register?returnUrl=<rel>` → Keycloak re-auths
|
|
1707
|
-
* the user (password) then runs the credential-creation ceremony, returning
|
|
1708
|
-
* the browser to `returnUrl?passkey=registered`;
|
|
1709
|
-
* - failure / cancel: the BFF redirects to `<login>?passkeyError=cancelled` or
|
|
1710
|
-
* `<login>?passkeyError=failed`.
|
|
1711
|
-
*
|
|
1712
|
-
* react-query-FREE by construction: there is NO fetch here at all — every
|
|
1713
|
-
* function is a pure `window.location` read or `window.location.assign`. The
|
|
1714
|
-
* login route group has no QueryClient provider, so the passkey login button
|
|
1715
|
-
* (which lives there) MUST avoid any react-query primitive; navigation satisfies
|
|
1716
|
-
* that trivially.
|
|
1717
|
-
*
|
|
1718
|
-
* All reads are SSR-safe: when `window` is undefined (server render / native)
|
|
1719
|
-
* they return a benign default rather than throwing.
|
|
1720
|
-
*/
|
|
1721
1697
|
/** The recognised passkey error codes the BFF sends back via `?passkeyError=`. */
|
|
1722
1698
|
type PasskeyErrorCode = 'cancelled' | 'failed';
|
|
1723
1699
|
/**
|
|
@@ -1949,6 +1925,97 @@ declare function resolvePostLoginRoute(user: BffUser, table: RoleRouteTable): st
|
|
|
1949
1925
|
*/
|
|
1950
1926
|
declare function resolveAccessibleRoutes(user: BffUser, table: RoleRouteTable): RoleRoute[];
|
|
1951
1927
|
|
|
1928
|
+
/**
|
|
1929
|
+
* `performBffLogout` — the shared logout sequencer.
|
|
1930
|
+
*
|
|
1931
|
+
* Every app hand-rolled its own logout ordering inside its `AuthProvider`, and
|
|
1932
|
+
* the orderings disagreed. Two of them (zygos-web, agora-web) navigated FIRST
|
|
1933
|
+
* and called the BFF second:
|
|
1934
|
+
*
|
|
1935
|
+
* ```ts
|
|
1936
|
+
* redirectTo('/(auth)/login'); // window.location.replace() → document unload
|
|
1937
|
+
* await bffAuthClient.logout(); // races the unload — may never be sent
|
|
1938
|
+
* ```
|
|
1939
|
+
*
|
|
1940
|
+
* That is wrong twice over:
|
|
1941
|
+
*
|
|
1942
|
+
* 1. **The BFF call can be cancelled.** A document navigation kills in-flight
|
|
1943
|
+
* fetches, so `POST /bff/logout` may never reach the server: the SPA looks
|
|
1944
|
+
* logged out while the httpOnly session cookie stays ALIVE. The `catch`
|
|
1945
|
+
* logged it "non-fatal", so the defect was silent.
|
|
1946
|
+
* 2. **The IdP session survives.** `BffAuthClient.logout()` ends the *identity
|
|
1947
|
+
* provider's* browser session by doing a top-level navigation to the IdP's
|
|
1948
|
+
* RP-initiated logout URL (only a real navigation carries the IdP's own
|
|
1949
|
+
* cookie — a back-channel POST cannot clear it). An app that navigates to
|
|
1950
|
+
* its own login route first pre-empts that navigation, so the IdP still
|
|
1951
|
+
* considers the user signed in and the next authorize round-trip silently
|
|
1952
|
+
* re-authenticates them. That is the "sign-out that signs you back in" bug
|
|
1953
|
+
* the client's own docs warn about.
|
|
1954
|
+
*
|
|
1955
|
+
* This helper owns the whole sequence so neither can be reintroduced per-app:
|
|
1956
|
+
*
|
|
1957
|
+
* 1. `onClearSession()` — drop local state immediately so the UI reflects the
|
|
1958
|
+
* sign-out right away (perceived performance; no spinner needed).
|
|
1959
|
+
* 2. `await client.logout({ redirect: false })` — let the network call SETTLE,
|
|
1960
|
+
* and take the IdP logout URL rather than letting the client navigate mid-
|
|
1961
|
+
* sequence. Errors are captured, never rethrown.
|
|
1962
|
+
* 3. Navigate LAST, exactly once, when nothing is in flight to cancel:
|
|
1963
|
+
* - an IdP logout URL → a top-level navigation to the IdP, which ends that
|
|
1964
|
+
* session and bounces the user back. `onRedirect` is deliberately NOT
|
|
1965
|
+
* called: two competing navigations would race, and the IdP round-trip
|
|
1966
|
+
* already returns the user to the app.
|
|
1967
|
+
* - otherwise (ROPC / OTP / device-PIN logins never had an IdP cookie, so
|
|
1968
|
+
* the URL is `null`) → `onRedirect()`, the app's own login route.
|
|
1969
|
+
*
|
|
1970
|
+
* Step 3 runs even when step 2 rejects: a BFF that is down must not trap the
|
|
1971
|
+
* user on a page they asked to leave. The local session is already gone, so the
|
|
1972
|
+
* client-side sign-out holds regardless.
|
|
1973
|
+
*
|
|
1974
|
+
* Headless and framework-free: it takes callbacks, so an app can pair it with
|
|
1975
|
+
* Redux, a context, expo-router, or `window.location` without this package
|
|
1976
|
+
* knowing about any of them.
|
|
1977
|
+
*/
|
|
1978
|
+
/**
|
|
1979
|
+
* The only part of a `BffAuthClient` this helper needs. Structural, so it is
|
|
1980
|
+
* trivially fakeable in tests and does not couple to the full client surface.
|
|
1981
|
+
*/
|
|
1982
|
+
interface BffLogoutClient {
|
|
1983
|
+
/**
|
|
1984
|
+
* `POST /bff/logout` — ends the server-side session. With `redirect: false`
|
|
1985
|
+
* it returns the IdP's RP-initiated logout URL (or `null` when the session
|
|
1986
|
+
* never involved an IdP browser cookie) instead of navigating there itself.
|
|
1987
|
+
*/
|
|
1988
|
+
logout: (options?: {
|
|
1989
|
+
redirect?: boolean;
|
|
1990
|
+
}) => Promise<string | null>;
|
|
1991
|
+
}
|
|
1992
|
+
/** Callbacks + client for {@link performBffLogout}. */
|
|
1993
|
+
interface PerformBffLogoutOptions {
|
|
1994
|
+
/** The BFF auth client whose `logout()` ends the server-side session. */
|
|
1995
|
+
client: BffLogoutClient;
|
|
1996
|
+
/** Drop local session state. Runs BEFORE the network call. Optional. */
|
|
1997
|
+
onClearSession?: () => void;
|
|
1998
|
+
/**
|
|
1999
|
+
* Navigate to the app's logged-out route. Runs only AFTER the network call
|
|
2000
|
+
* settles, and only when there is no IdP logout URL to honour. Optional.
|
|
2001
|
+
*/
|
|
2002
|
+
onRedirect?: () => void;
|
|
2003
|
+
/** Observe a failed logout step (e.g. to log it). Never rethrown. Optional. */
|
|
2004
|
+
onError?: (error: Error) => void;
|
|
2005
|
+
/**
|
|
2006
|
+
* Test seam: perform the top-level navigation to the IdP logout URL. Defaults
|
|
2007
|
+
* to `window.location.assign`. Must be a real navigation — a `fetch` here
|
|
2008
|
+
* would not carry the IdP cookie and would silently fail to end the session.
|
|
2009
|
+
*/
|
|
2010
|
+
navigateToIdp?: (url: string) => void;
|
|
2011
|
+
}
|
|
2012
|
+
/**
|
|
2013
|
+
* End the session: clear locally, await the BFF, then navigate exactly once.
|
|
2014
|
+
*
|
|
2015
|
+
* Never rejects — callers may `void` it safely.
|
|
2016
|
+
*/
|
|
2017
|
+
declare function performBffLogout(options: Readonly<PerformBffLogoutOptions>): Promise<void>;
|
|
2018
|
+
|
|
1952
2019
|
/**
|
|
1953
2020
|
* The discrete ways a password can fail the shared client-side policy.
|
|
1954
2021
|
*
|
|
@@ -1994,4 +2061,4 @@ declare function validatePasswordPolicy(password: string): PasswordPolicyError[]
|
|
|
1994
2061
|
/** `true` when the password satisfies every policy rule. */
|
|
1995
2062
|
declare function isPasswordValid(password: string): boolean;
|
|
1996
2063
|
|
|
1997
|
-
export { AuthScreen, type AuthScreenProps, AuthTestIds, type AuthTheme, type AuthThemeColors, AuthThemeProvider, type AuthThemeProviderProps, type AuthThemeRadii, type AuthThemeSpacing, type AuthThemeTypography, BffAuthStatus, type BffDeviceState, type BffLoginConfig, type CreateBffAuthClientOptions, DEFAULT_AUTH_CARD_MAX_WIDTH, DEFAULT_DEVICE_PIN_ENROLL_LABELS, DEFAULT_DEVICE_PIN_SETTINGS_LABELS, DEFAULT_DEVICE_PIN_UNLOCK_LABELS, DEFAULT_FORGOT_PASSWORD_FIELDS_LABELS, DEFAULT_FORGOT_PASSWORD_LABELS, DEFAULT_LOGIN_LABELS, DEFAULT_OTP_LABELS, DEFAULT_PASSKEY_LOGIN_LABELS, DEFAULT_PASSKEY_SETTINGS_LABELS, DEFAULT_PIN_LABELS, DEFAULT_PREFERRED_METHOD_HINT_LABELS, DEFAULT_PREFERRED_METHOD_SETTINGS_LABELS, DEFAULT_RESET_PASSWORD_LABELS, DEVICE_PIN_ALLOWED_DIGITS, DEVICE_PIN_DEFAULT_DIGITS, type DevicePinCapableClient, type DevicePinDisableCapableClient, type DevicePinEnrollCapableClient, DevicePinEnrollErrorKey, DevicePinEnrollForm, type DevicePinEnrollFormProps, type DevicePinEnrollLabels, type DevicePinEnrollResult, DevicePinErrorKey, DevicePinInput, type DevicePinInputProps, DevicePinLengthPicker, type DevicePinLengthPickerProps, DevicePinOffer, type DevicePinOfferProps, DevicePinSettingsCard, type DevicePinSettingsCardProps, type DevicePinSettingsLabels, type DevicePinUnlockCapableClient, type DevicePinUnlockLabels, type DevicePinUnlockResult, DevicePinUnlockScreen, type DevicePinUnlockScreenProps, type DevicePinUnlockedUser, ForgotPasswordFields, type ForgotPasswordFieldsLabels, type ForgotPasswordFieldsProps, ForgotPasswordForm, type ForgotPasswordFormLabels, type ForgotPasswordFormProps, type LoginConfigCapableClient, LoginForm, type LoginFormLabels, type LoginFormProps, OtpForm, type OtpFormLabels, type OtpFormProps, OtpLoginStep, PASSWORD_MAX_LENGTH, PASSWORD_MIN_LENGTH, PasskeyCeremonyMode, PasskeyCeremonyStatus, type PasskeyErrorCode, PasskeyLoginButton, type PasskeyLoginButtonProps, type PasskeyLoginLabels, PasskeySettingsCard, type PasskeySettingsCardProps, type PasskeySettingsLabels, PasswordPolicyError, PinForm, type PinFormLabels, type PinFormProps, type PreferencesClientOptions, type PreferredMethodClient, PreferredMethodHint, type PreferredMethodHintLabels, type PreferredMethodHintProps, PreferredMethodSettingsCard, type PreferredMethodSettingsCardProps, type PreferredMethodSettingsLabels, ResetPasswordError, ResetPasswordForm, type ResetPasswordFormLabels, type ResetPasswordFormProps, type RoleRoute, type RoleRouteTable, type UseBffAuthOptions, type UseBffAuthResult, type UseBffForgotPasswordOptions, type UseBffLoginConfigResult, type UseBffResetPasswordOptions, type UseDevicePinDisableArgs, type UseDevicePinDisableResult, type UseDevicePinEnrollArgs, type UseDevicePinEnrollResult, type UseDevicePinUnlockArgs, type UseDevicePinUnlockResult, type UseForgotPasswordSubmitArgs, type UseForgotPasswordSubmitResult, type UseOtpLoginOptions, type UseOtpLoginResult, type UsePasskeyCeremonyOptions, type UsePasskeyCeremonyResult, type UsePinLoginOptions, type UsePinLoginResult, type UsePreferredMethodSettingArgs, type UsePreferredMethodSettingResult, type UseResetPasswordFormArgs, type UseResetPasswordFormResult, cachePreferredMethod, clearCachedPreferredMethod, collectUserRoles, createBffAuthClient, createPreferencesClient, defaultAuthTheme, isAllowedPinDigits, isPasswordValid, isValidForgotPasswordEmail, readCachedPreferredMethod, readPasskeyError, readPasskeyRegistered, resolveAccessibleRoutes, resolvePostLoginRoute, startPasskeyLogin, startPasskeyRegistration, syncPreferredMethodFromServer, useAuthTheme, useBffAuth, useBffForgotPassword, useBffLoginConfig, useBffResetPassword, useDevicePinDisable, useDevicePinEnroll, useDevicePinUnlock, useForgotPasswordSubmit, useOtpLogin, usePasskeyCeremony, usePinLogin, usePreferredMethodSetting, useResetPasswordForm, validatePasswordPolicy, withTestIdPrefix };
|
|
2064
|
+
export { AuthScreen, type AuthScreenProps, AuthTestIds, type AuthTheme, type AuthThemeColors, AuthThemeProvider, type AuthThemeProviderProps, type AuthThemeRadii, type AuthThemeSpacing, type AuthThemeTypography, BffAuthStatus, type BffDeviceState, type BffLoginConfig, type BffLogoutClient, type CreateBffAuthClientOptions, DEFAULT_AUTH_CARD_MAX_WIDTH, DEFAULT_DEVICE_PIN_ENROLL_LABELS, DEFAULT_DEVICE_PIN_SETTINGS_LABELS, DEFAULT_DEVICE_PIN_UNLOCK_LABELS, DEFAULT_FORGOT_PASSWORD_FIELDS_LABELS, DEFAULT_FORGOT_PASSWORD_LABELS, DEFAULT_LOGIN_LABELS, DEFAULT_OTP_LABELS, DEFAULT_PASSKEY_LOGIN_LABELS, DEFAULT_PASSKEY_SETTINGS_LABELS, DEFAULT_PIN_LABELS, DEFAULT_PREFERRED_METHOD_HINT_LABELS, DEFAULT_PREFERRED_METHOD_SETTINGS_LABELS, DEFAULT_RESET_PASSWORD_LABELS, DEVICE_PIN_ALLOWED_DIGITS, DEVICE_PIN_DEFAULT_DIGITS, type DevicePinCapableClient, type DevicePinDisableCapableClient, type DevicePinEnrollCapableClient, DevicePinEnrollErrorKey, DevicePinEnrollForm, type DevicePinEnrollFormProps, type DevicePinEnrollLabels, type DevicePinEnrollResult, DevicePinErrorKey, DevicePinInput, type DevicePinInputProps, DevicePinLengthPicker, type DevicePinLengthPickerProps, DevicePinOffer, type DevicePinOfferProps, DevicePinSettingsCard, type DevicePinSettingsCardProps, type DevicePinSettingsLabels, type DevicePinUnlockCapableClient, type DevicePinUnlockLabels, type DevicePinUnlockResult, DevicePinUnlockScreen, type DevicePinUnlockScreenProps, type DevicePinUnlockedUser, ForgotPasswordFields, type ForgotPasswordFieldsLabels, type ForgotPasswordFieldsProps, ForgotPasswordForm, type ForgotPasswordFormLabels, type ForgotPasswordFormProps, type LoginConfigCapableClient, LoginForm, type LoginFormLabels, type LoginFormProps, OtpForm, type OtpFormLabels, type OtpFormProps, OtpLoginStep, PASSWORD_MAX_LENGTH, PASSWORD_MIN_LENGTH, PasskeyCeremonyMode, PasskeyCeremonyStatus, type PasskeyErrorCode, PasskeyLoginButton, type PasskeyLoginButtonProps, type PasskeyLoginLabels, PasskeySettingsCard, type PasskeySettingsCardProps, type PasskeySettingsLabels, PasswordPolicyError, type PerformBffLogoutOptions, PinForm, type PinFormLabels, type PinFormProps, type PreferencesClientOptions, type PreferredMethodClient, PreferredMethodHint, type PreferredMethodHintLabels, type PreferredMethodHintProps, PreferredMethodSettingsCard, type PreferredMethodSettingsCardProps, type PreferredMethodSettingsLabels, ResetPasswordError, ResetPasswordForm, type ResetPasswordFormLabels, type ResetPasswordFormProps, type RoleRoute, type RoleRouteTable, type UseBffAuthOptions, type UseBffAuthResult, type UseBffForgotPasswordOptions, type UseBffLoginConfigResult, type UseBffResetPasswordOptions, type UseDevicePinDisableArgs, type UseDevicePinDisableResult, type UseDevicePinEnrollArgs, type UseDevicePinEnrollResult, type UseDevicePinUnlockArgs, type UseDevicePinUnlockResult, type UseForgotPasswordSubmitArgs, type UseForgotPasswordSubmitResult, type UseOtpLoginOptions, type UseOtpLoginResult, type UsePasskeyCeremonyOptions, type UsePasskeyCeremonyResult, type UsePinLoginOptions, type UsePinLoginResult, type UsePreferredMethodSettingArgs, type UsePreferredMethodSettingResult, type UseResetPasswordFormArgs, type UseResetPasswordFormResult, cachePreferredMethod, clearCachedPreferredMethod, collectUserRoles, createBffAuthClient, createPreferencesClient, defaultAuthTheme, isAllowedPinDigits, isPasswordValid, isValidForgotPasswordEmail, performBffLogout, readCachedPreferredMethod, readPasskeyError, readPasskeyRegistered, resolveAccessibleRoutes, resolvePostLoginRoute, startPasskeyLogin, startPasskeyRegistration, syncPreferredMethodFromServer, useAuthTheme, useBffAuth, useBffForgotPassword, useBffLoginConfig, useBffResetPassword, useDevicePinDisable, useDevicePinEnroll, useDevicePinUnlock, useForgotPasswordSubmit, useOtpLogin, usePasskeyCeremony, usePinLogin, usePreferredMethodSetting, useResetPasswordForm, validatePasswordPolicy, withTestIdPrefix };
|
package/dist/index.js
CHANGED
|
@@ -2520,6 +2520,18 @@ var PasskeyCeremonyMode = /* @__PURE__ */ ((PasskeyCeremonyMode2) => {
|
|
|
2520
2520
|
return PasskeyCeremonyMode2;
|
|
2521
2521
|
})(PasskeyCeremonyMode || {});
|
|
2522
2522
|
|
|
2523
|
+
// src/passkey/browserLocation.ts
|
|
2524
|
+
function getBrowserLocation() {
|
|
2525
|
+
if (typeof window === "undefined") {
|
|
2526
|
+
return null;
|
|
2527
|
+
}
|
|
2528
|
+
const browserLocation = window.location;
|
|
2529
|
+
if (browserLocation === void 0) {
|
|
2530
|
+
return null;
|
|
2531
|
+
}
|
|
2532
|
+
return browserLocation;
|
|
2533
|
+
}
|
|
2534
|
+
|
|
2523
2535
|
// src/passkey/passkeyNavigation.ts
|
|
2524
2536
|
var PASSKEY_LOGIN_ENDPOINT = "/bff/passkey/login";
|
|
2525
2537
|
var PASSKEY_REGISTER_ENDPOINT = "/bff/passkey/register";
|
|
@@ -2533,22 +2545,25 @@ function buildNavigationUrl(endpoint, returnUrl) {
|
|
|
2533
2545
|
return `${endpoint}?${RETURN_URL_PARAM}=${encodeURIComponent(returnUrl)}`;
|
|
2534
2546
|
}
|
|
2535
2547
|
function readSearchParams() {
|
|
2536
|
-
|
|
2548
|
+
const browserLocation = getBrowserLocation();
|
|
2549
|
+
if (browserLocation === null) {
|
|
2537
2550
|
return null;
|
|
2538
2551
|
}
|
|
2539
|
-
return new URLSearchParams(
|
|
2552
|
+
return new URLSearchParams(browserLocation.search);
|
|
2540
2553
|
}
|
|
2541
2554
|
function startPasskeyLogin(returnUrl) {
|
|
2542
|
-
|
|
2555
|
+
const browserLocation = getBrowserLocation();
|
|
2556
|
+
if (browserLocation === null) {
|
|
2543
2557
|
return;
|
|
2544
2558
|
}
|
|
2545
|
-
|
|
2559
|
+
browserLocation.assign(buildNavigationUrl(PASSKEY_LOGIN_ENDPOINT, returnUrl));
|
|
2546
2560
|
}
|
|
2547
2561
|
function startPasskeyRegistration(returnUrl) {
|
|
2548
|
-
|
|
2562
|
+
const browserLocation = getBrowserLocation();
|
|
2563
|
+
if (browserLocation === null) {
|
|
2549
2564
|
return;
|
|
2550
2565
|
}
|
|
2551
|
-
|
|
2566
|
+
browserLocation.assign(buildNavigationUrl(PASSKEY_REGISTER_ENDPOINT, returnUrl));
|
|
2552
2567
|
}
|
|
2553
2568
|
function readPasskeyError() {
|
|
2554
2569
|
const params = readSearchParams();
|
|
@@ -2725,8 +2740,9 @@ function usePasskeyCeremony(optionsArg) {
|
|
|
2725
2740
|
onSuccess(user);
|
|
2726
2741
|
return;
|
|
2727
2742
|
}
|
|
2728
|
-
|
|
2729
|
-
|
|
2743
|
+
const browserLocation = getBrowserLocation();
|
|
2744
|
+
if (mode === "login" /* Login */ && browserLocation !== null) {
|
|
2745
|
+
browserLocation.assign(returnUrl);
|
|
2730
2746
|
}
|
|
2731
2747
|
},
|
|
2732
2748
|
[mode, onSuccess, returnUrl]
|
|
@@ -2848,10 +2864,11 @@ function PasskeyLoginButton({
|
|
|
2848
2864
|
}
|
|
2849
2865
|
var DEFAULT_RETURN_PATH = "/";
|
|
2850
2866
|
function readCurrentPath() {
|
|
2851
|
-
|
|
2867
|
+
const browserLocation = getBrowserLocation();
|
|
2868
|
+
if (browserLocation === null) {
|
|
2852
2869
|
return DEFAULT_RETURN_PATH;
|
|
2853
2870
|
}
|
|
2854
|
-
return
|
|
2871
|
+
return browserLocation.pathname;
|
|
2855
2872
|
}
|
|
2856
2873
|
function PasskeySettingsCard({
|
|
2857
2874
|
returnUrl,
|
|
@@ -3269,6 +3286,43 @@ function resolveAccessibleRoutes(user, table) {
|
|
|
3269
3286
|
return table.routes.filter((entry) => userRoles.has(entry.role));
|
|
3270
3287
|
}
|
|
3271
3288
|
|
|
3289
|
+
// src/session/performBffLogout.ts
|
|
3290
|
+
function toError4(caught) {
|
|
3291
|
+
return caught instanceof Error ? caught : new Error(String(caught));
|
|
3292
|
+
}
|
|
3293
|
+
function runGuarded(callback, onError) {
|
|
3294
|
+
if (callback === void 0) {
|
|
3295
|
+
return;
|
|
3296
|
+
}
|
|
3297
|
+
try {
|
|
3298
|
+
callback();
|
|
3299
|
+
} catch (caught) {
|
|
3300
|
+
onError?.(toError4(caught));
|
|
3301
|
+
}
|
|
3302
|
+
}
|
|
3303
|
+
function assignLocation(url) {
|
|
3304
|
+
if (typeof window === "undefined") {
|
|
3305
|
+
return;
|
|
3306
|
+
}
|
|
3307
|
+
window.location.assign(url);
|
|
3308
|
+
}
|
|
3309
|
+
async function performBffLogout(options) {
|
|
3310
|
+
const { client, onClearSession, onRedirect, onError, navigateToIdp = assignLocation } = options;
|
|
3311
|
+
runGuarded(onClearSession, onError);
|
|
3312
|
+
let idpLogoutUrl = null;
|
|
3313
|
+
try {
|
|
3314
|
+
idpLogoutUrl = await client.logout({ redirect: false });
|
|
3315
|
+
} catch (caught) {
|
|
3316
|
+
onError?.(toError4(caught));
|
|
3317
|
+
}
|
|
3318
|
+
if (idpLogoutUrl !== null) {
|
|
3319
|
+
const url = idpLogoutUrl;
|
|
3320
|
+
runGuarded(() => navigateToIdp(url), onError);
|
|
3321
|
+
return;
|
|
3322
|
+
}
|
|
3323
|
+
runGuarded(onRedirect, onError);
|
|
3324
|
+
}
|
|
3325
|
+
|
|
3272
3326
|
Object.defineProperty(exports, "BffAuthClient", {
|
|
3273
3327
|
enumerable: true,
|
|
3274
3328
|
get: function () { return authClient.BffAuthClient; }
|
|
@@ -3331,6 +3385,7 @@ exports.defaultAuthTheme = defaultAuthTheme;
|
|
|
3331
3385
|
exports.isAllowedPinDigits = isAllowedPinDigits;
|
|
3332
3386
|
exports.isPasswordValid = isPasswordValid;
|
|
3333
3387
|
exports.isValidForgotPasswordEmail = isValidForgotPasswordEmail;
|
|
3388
|
+
exports.performBffLogout = performBffLogout;
|
|
3334
3389
|
exports.readCachedPreferredMethod = readCachedPreferredMethod;
|
|
3335
3390
|
exports.readPasskeyError = readPasskeyError;
|
|
3336
3391
|
exports.readPasskeyRegistered = readPasskeyRegistered;
|