@rkosafo/cai.components
Version:
This package is under development and not ready for public use.
146 lines (145 loc) • 5.2 kB
JavaScript
import Keycloak from 'keycloak-js';
export function createAuthStore() {
return {
isLoading: true,
isAuthenticated: false,
accessToken: '',
idToken: '',
userInfo: null,
authError: '',
userIsFound: false
};
}
export class KeycloakService {
keycloak = null;
initialized = false;
store;
fetchUserInfo;
onAuthenticated;
onLogout;
onError;
constructor(store, fetchUserInfo, callbacks) {
this.store = store;
this.fetchUserInfo = fetchUserInfo;
this.onAuthenticated = callbacks?.onAuthenticated;
this.onLogout = callbacks?.onLogout;
this.onError = callbacks?.onError;
}
async init(config, initOptions = { onLoad: 'login-required', checkLoginIframe: false }) {
try {
this.keycloak = new Keycloak(config);
const authenticated = await this.keycloak.init(initOptions);
if (authenticated) {
await this.setTokenDetails(this.keycloak.idTokenParsed);
}
else {
this.setTokenDetails(null);
}
this.initialized = true;
this.store.isLoading = false;
}
catch (error) {
this.initialized = false;
const errorMessage = error instanceof Error ? error.message : 'Initialization failed';
this.store.authError = errorMessage;
this.onError?.(errorMessage);
this.store.isLoading = false;
}
}
async setTokenDetails(details) {
if (!details) {
this.store.isAuthenticated = false;
this.store.accessToken = '';
this.store.idToken = '';
this.store.userInfo = null;
return;
}
try {
this.store.isAuthenticated = true;
this.store.accessToken = this.keycloak.token;
this.store.idToken = this.keycloak.idToken;
this.store.authError = '';
// Fetch user info using provided function
const meRet = await this.fetchUserInfo(this.keycloak.token);
let extras = {};
if (meRet.success) {
extras = meRet.data;
this.store.userIsFound = true;
}
else {
this.store.authError = meRet.message || 'Failed to fetch user info';
this.store.userIsFound = meRet.code === 402;
}
const userInfo = {
id: extras.id,
email: extras?.email || details.email,
firstName: extras?.firstName || details.given_name,
lastName: extras?.lastName || details.family_name,
otherNames: '',
name: extras?.name || extras?.fullName || details.name,
username: extras?.name || extras?.fullName || details.preferred_username,
initials: extras?.name ||
extras?.fullName ||
details.name
?.split(' ')
.filter((x) => x.length > 1)
.map((x) => x[0])
.join('') ||
'',
department: extras?.department || '',
departmentId: extras?.departmentId,
role: extras?.role,
roleId: extras?.roleId,
tags: extras?.tags ?? [],
permissions: extras?.permissions ?? [],
type: extras?.type,
activeDashboardId: extras?.activeDashboardId,
district: extras?.district,
phoneNumber: extras?.phoneNumber || '',
profileImage: extras?.profileImage || '',
status: extras?.status || ''
};
this.store.userInfo = userInfo;
this.onAuthenticated?.({ keycloakUser: userInfo, queryUser: meRet.data });
}
catch (error) {
const errorMessage = error instanceof Error ? error.message : 'Failed to set token details';
this.store.authError = errorMessage;
this.onError?.(errorMessage);
}
}
login() {
if (this.initialized && this.keycloak) {
this.keycloak.login();
}
}
async refreshToken() {
if (!this.initialized || !this.keycloak)
return;
try {
const refreshed = await this.keycloak.updateToken(30);
if (refreshed) {
await this.setTokenDetails(this.keycloak.idTokenParsed);
}
}
catch (error) {
const errorMessage = error instanceof Error ? error.message : 'Token refresh failed';
this.store.authError = errorMessage;
this.onError?.(errorMessage);
}
}
logout() {
if (!this.initialized || !this.keycloak)
return;
this.keycloak.logout();
this.store.userInfo = null;
this.store.isAuthenticated = false;
this.onLogout?.();
}
getKeycloakInstance() {
return this.keycloak;
}
isInitialized() {
return this.initialized;
}
}