import { HoistBase } from '@xh/hoist/core'; import { Token } from '@xh/hoist/security/Token'; import { AccessTokenSpec, TokenMap } from './Types'; export type LoginMethod = 'REDIRECT' | 'POPUP'; /** * Base configuration shared by all OAuth client implementations. Extended by * {@link MsalClientConfig} and {@link AuthZeroClientConfig} with provider-specific options. * * See the security package README (`security/README.md`) for authentication architecture * and setup guidance. * * @see BaseOAuthClient */ export interface BaseOAuthClientConfig { /** Client ID (GUID) of your app registered with your Oauth provider. */ clientId: string; /** * Redirect URL where authentication responses can be received by your application. * It must exactly match one of the redirect URIs registered in the relevant OAuth authority. * Default is 'APP_BASE_URL' which will be replaced with the current app's base URL. */ redirectUrl?: 'APP_BASE_URL' | string; /** * Redirect URL after a successful logout. * Default is 'APP_BASE_URL' which will be replaced with the current app's base URL. */ postLogoutRedirectUrl?: 'APP_BASE_URL' | string; /** The method used for logging in on desktop. Default is 'REDIRECT'. */ loginMethodDesktop?: LoginMethod; /** The method used for logging in on mobile. Default is 'REDIRECT'. */ loginMethodMobile?: LoginMethod; /** * Governs an optional refresh timer that will work to keep the tokens fresh. * * A typical refresh will use the underlying provider cache, and should not result in * network activity. However, if any token would expire before the next autoRefresh, * this client will force a call to the underlying provider to get the token. * * In order to allow aging tokens to be replaced in a timely manner, this value should be * significantly shorter than both the minimum token lifetime that will be * returned by the underlying API. * * Default is -1, disabling this behavior. */ autoRefreshSecs?: number; /** * Scopes to request - if any - beyond the core `['openid', 'email']` scopes, which * this client will always request. */ idScopes?: string[]; /** * Optional spec for access tokens to be loaded and maintained to support access to one or more * different back-end resources, distinct from the core Hoist auth flow via ID token. * * Map of key to a spec for an access token. The key is an arbitrary, app-determined string * used to retrieve the loaded token via {@link getAccessTokenAsync}. The spec is implementation * specific, but will typically include scopes to be loaded for the access token and potentially * other metadata required by the underlying provider. */ accessTokens?: Record; /** * True to allow this client to try to re-login interactively (via pop-up) if tokens begin * failing to load due to specific provider exceptions indicating user interaction is required. * This can happen, for example, if a token expires and the refresh token is expired or * invalidated during the lifetime of the client. Default is false and retry will not be * attempted. */ reloginEnabled?: boolean; /** * Maximum time for (interactive) re-login. * * Set to a reasonably fixed amount of time, to allow user to type in password and complete * MFA, but not so long as to allow a problematic build-up of application requests. * Default 60 seconds; */ reloginTimeoutSecs?: number; } /** * Implementations of this class coordinate OAuth-based login and token provision. Apps can use a * suitable concrete implementation to power a client-side OauthService. See `MsalClient` and * `AuthZeroClient` * * Initialize such a service and this client within an app's primary {@link HoistAuthModel} to use * the tokens it acquires to authenticate with the Hoist server. (Note this requires a suitable * server-side `AuthenticationService` implementation to validate the token and actually resolve * the user.) On init, the client impl will initiate a pop-up or redirect flow as necessary. */ export declare abstract class BaseOAuthClient, S extends AccessTokenSpec> extends HoistBase { /** Config loaded from UI server + init method. */ protected config: C; /** ID Scopes */ protected idScopes: string[]; /** Specification for Access Tokens */ protected accessSpecs: Record; private timer; private lastRefreshAttempt; private TIMER_INTERVAL; private pendingRelogin; private lastRelogin; constructor(config: C); /** * Main entry point for this object. */ initAsync(): Promise; /** * Request an interactive login with the underlying OAuth provider. */ loginAsync(method?: LoginMethod): Promise; /** * Request a full logout from the underlying OAuth provider. */ logoutAsync(): Promise; /** * Get an ID token. */ getIdTokenAsync(): Promise; /** * Get an Access token. */ getAccessTokenAsync(key: string): Promise; /** * Get all configured tokens. */ getAllTokensAsync(opts?: { eagerOnly?: boolean; useCache?: boolean; }): Promise; /** * The last authenticated OAuth username. * * Provided to facilitate more efficient re-login via SSO or otherwise. Cleared on logout. * Note: not necessarily a currently authenticated user, and not necessarily the Hoist username. */ getSelectedUsername(): string; /** * Set the last authenticated OAuth username. * See `getSelectedUsername()`. */ setSelectedUsername(username: string): void; protected abstract doInitAsync(): Promise; protected abstract doLoginPopupAsync(): Promise; protected abstract doLoginRedirectAsync(): Promise; protected abstract fetchIdTokenAsync(useCache: boolean): Promise; protected abstract fetchAccessTokenAsync(spec: S, useCache: boolean): Promise; protected abstract doLogoutAsync(): Promise; protected abstract interactiveLoginNeeded(exception: unknown): boolean; protected get redirectUrl(): string; protected get postLogoutRedirectUrl(): string; protected get loginMethod(): LoginMethod; protected get baseUrl(): string; protected get blankUrl(): string; protected popupBlockerErrorMessage: String; protected defaultErrorMsg: String; /** * Call before redirect flow to snapshot any URL-based routing state that should be restored * after redirect * * @returns key - key for re-accessing this state, to be round-tripped with redirect. */ protected captureRedirectState(): string; /** * Call after redirect flow to rehydrate URL-based routing state. * * @param key - key for re-accessing this state, as round-tripped with redirect. */ protected restoreRedirectState(key: string): void; /** Call after requesting the provider library redirect the user away for auth. */ protected maskAfterRedirectAsync(): Promise; protected fetchAllTokensAsync(opts?: { eagerOnly?: boolean; useCache?: boolean; }): Promise; protected getLocalStorage(key: string, defaultValue?: any): any; protected setLocalStorage(key: string, value: any): void; private fetchIdTokenSafeAsync; private getWithRetry; private rethrowWrapped; private getLoginTask; private onTimerAsync; private logTokensDebug; }