bizmatch-project/bizmatch/src/keycloak.ts

87 lines
3.3 KiB
TypeScript

import { KeycloakAdapter, KeycloakInstance, KeycloakLoginOptions, KeycloakLogoutOptions, KeycloakRegisterOptions } from 'keycloak-js';
import { createLogger } from './app/utils/utils';
const logger = createLogger('keycloak');
export type OptionsOrProvider<T> = Partial<T> | (() => Partial<T>);
/**
* Create and immediately resolve a KeycloakPromise
*/
const createPromise = () => new Promise<void>(resolve => resolve());
/**
* Resolve OptionsOrProvider: if it's an function, execute it, otherwise return it.
*/
const resolveOptions = <T>(opt: OptionsOrProvider<T>): Partial<T> => (typeof opt === 'function' ? opt() : opt);
/**
*
* Update options with the overrides given as OptionsOrProvider
*
* @param options
* @param overrides
* @returns
*/
const updateOptions = <T>(options: T, overrides: OptionsOrProvider<T>): T => Object.assign(options ?? <T>{}, resolveOptions(overrides));
/**
* Keycloak adapter that supports options customization.
*
* All options can either be given as lazily evaluated provider functions (that will be evaluated
* right before navigating) or eagerly evaluated objects. These options will have precedence
* over options passed by keycloak-js.
*
* Cf. https://www.keycloak.org/docs/15.0/securing_apps/#custom-adapters
*
* Actual implementation copied more or less verbatim from
* https://github.com/keycloak/keycloak-js-bower/blob/10.0.2/dist/keycloak.js#L1136
*
* @param kc Function that returns a Keycloak instance
* @param loginOptions login options
* @param logoutOptions logout options
* @param registerOptions register options
* @returns KeycloakAdapter
*/
export function customKeycloakAdapter(
kc: () => KeycloakInstance,
loginOptions: OptionsOrProvider<KeycloakLoginOptions> = {},
logoutOptions: OptionsOrProvider<KeycloakLogoutOptions> = {},
registerOptions: OptionsOrProvider<KeycloakRegisterOptions> = {},
): KeycloakAdapter {
return {
login: (options?: KeycloakLoginOptions): Promise<void> => {
updateOptions(options, loginOptions);
logger.info('Executing login. Options: ', options);
window.location.replace(kc().createLoginUrl(options));
return createPromise();
},
logout: (options?: KeycloakLogoutOptions): Promise<void> => {
updateOptions(options, logoutOptions);
logger.info('Executing logout. Options: ', options);
window.location.replace(kc().createLogoutUrl(options));
return createPromise();
},
register: (options?: KeycloakRegisterOptions): Promise<void> => {
updateOptions(options, registerOptions);
logger.info('Executing register. Options: ', options);
window.location.replace(kc().createRegisterUrl(options));
return createPromise();
},
accountManagement: (): Promise<void> => {
const accountUrl = kc().createAccountUrl();
logger.info('Executing account management');
if (typeof accountUrl !== 'undefined') {
window.location.href = accountUrl;
} else {
throw new Error('Not supported by the OIDC server');
}
return createPromise();
},
redirectUri: (options: { redirectUri: string }) => {
if (options?.redirectUri) {
return options.redirectUri;
}
if (kc().redirectUri) {
return kc().redirectUri;
}
return window.location.href;
},
};
}