87 lines
3.3 KiB
TypeScript
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;
|
|
},
|
|
};
|
|
}
|