@josempgon/vue-keycloak
Version:
Keycloak plugin for Vue 3 with Composition API
207 lines (199 loc) • 6.39 kB
JavaScript
import Keycloak from 'keycloak-js';
import { shallowRef, reactive, toRefs } from 'vue';
function isArray(value) {
return Array.isArray(value);
}
function isFunction(fun) {
return typeof fun === 'function';
}
function isNil(value) {
return value === undefined || value === null;
}
function isString(value) {
return typeof value === 'string';
}
function isErrorLike(value) {
return value instanceof Error || isString(value) || isString(value === null || value === void 0 ? void 0 : value.error);
}
const keycloak = shallowRef();
const state = reactive({
isAuthenticated: false,
hasFailed: false,
error: null,
isPending: false,
token: '',
decodedToken: {},
username: '',
userId: '',
roles: [],
resourceRoles: {},
});
const setKeycloak = (value) => {
keycloak.value = value;
};
const setToken = (token, tokenParsed) => {
var _a, _b;
state.token = token;
const content = tokenParsed;
state.decodedToken = content;
state.roles = content.realm_access ? content.realm_access.roles : [];
state.username = ((_a = content.preferred_username) !== null && _a !== void 0 ? _a : '');
state.userId = (_b = content.sub) !== null && _b !== void 0 ? _b : '';
state.resourceRoles = content.resource_access
? Object.fromEntries(Object.entries(content.resource_access).map(([key, value]) => [key, value.roles]))
: {};
};
const clearToken = () => {
state.token = '';
state.decodedToken = {};
state.roles = [];
state.username = '';
state.userId = '';
state.resourceRoles = {};
};
const hasFailed = (value, err) => {
state.hasFailed = value;
if (err instanceof Error) {
state.error = err;
}
else if (isString(err === null || err === void 0 ? void 0 : err.error)) {
state.error = new Error(err.error);
}
else if (isString(err)) {
state.error = new Error(err);
}
else {
state.error = new Error('Unknown');
}
state.error.name = '[vue-keycloak]';
console.error(state.error);
};
const isPending = (value) => {
state.isPending = value;
};
const isAuthenticated = (value) => {
state.isAuthenticated = value;
};
let $keycloak = undefined;
let creationFailed = false;
async function updateToken(minValidity) {
const keycloak = $keycloak;
if (isNil(keycloak)) {
throw new Error('[vue-keycloak] Keycloak is not initialised. Call createKeycloak() first.');
}
try {
await keycloak.updateToken(minValidity);
const { token, tokenParsed } = keycloak;
if (isNil(token) || isNil(tokenParsed)) {
throw new Error('Failed to refresh the access token');
}
setToken(token, tokenParsed);
return token;
}
catch (err) {
if (!keycloak.authenticated) {
isAuthenticated(false);
clearToken();
}
const rejectionReason = isErrorLike(err) ? err : new Error('Failed to refresh the access token');
hasFailed(true, rejectionReason);
throw rejectionReason;
}
}
async function getToken(minValidity = 10) {
return updateToken(minValidity);
}
function createKeycloak(config) {
creationFailed = false;
try {
$keycloak = new Keycloak(config);
setKeycloak($keycloak);
}
catch (err) {
$keycloak = undefined;
creationFailed = true;
hasFailed(true, isNil(err) ? new Error('Failed to create the keycloak adapter') : err);
}
return $keycloak;
}
async function initKeycloak(initConfig) {
try {
isPending(true);
const keycloak = $keycloak;
if (isNil(keycloak)) {
if (!creationFailed) {
hasFailed(true, new Error('Keycloak is not initialised. Call createKeycloak() first.'));
}
return;
}
const _isAuthenticated = await keycloak.init(initConfig);
isAuthenticated(_isAuthenticated);
if (!isNil(keycloak.token) && !isNil(keycloak.tokenParsed)) {
setToken(keycloak.token, keycloak.tokenParsed);
}
}
catch (err) {
isAuthenticated(false);
hasFailed(true, isNil(err) ? new Error('Failed to initialize the keycloak adapter') : err);
}
finally {
isPending(false);
}
}
const useKeycloak = () => {
return {
keycloak,
...toRefs(state),
hasRoles: (roles) => isArray(roles) && roles.length > 0 && state.isAuthenticated && roles.every(role => state.roles.includes(role)),
hasResourceRoles: (roles, resource) => isArray(roles) &&
roles.length > 0 &&
!isNil(resource) &&
state.isAuthenticated &&
!isNil(state.resourceRoles) &&
isArray(state.resourceRoles[resource]) &&
roles.every(role => state.resourceRoles[resource].includes(role)),
};
};
const defaultInitConfig = {
flow: 'standard',
checkLoginIframe: false,
onLoad: 'login-required',
};
const vueKeycloak = {
install: async (app, options) => {
isPending(true);
if (isNil(options)) {
isPending(false);
hasFailed(true, new Error('The VueKeycloakPluginConfig is required'));
return;
}
let keycloakPluginConfig;
if (isFunction(options)) {
try {
keycloakPluginConfig = await options();
}
catch (err) {
isPending(false);
hasFailed(true, isNil(err) ? new Error('The KeycloakConfigAsyncFactory failed') : err);
return;
}
}
else {
keycloakPluginConfig = options;
}
if (isNil(keycloakPluginConfig.config)) {
isPending(false);
hasFailed(true, new Error('The KeycloakConfig is required'));
return;
}
const keycloakConfig = keycloakPluginConfig.config;
const keycloakInitOptions = !isNil(keycloakPluginConfig.initOptions)
? { ...defaultInitConfig, ...keycloakPluginConfig.initOptions }
: defaultInitConfig;
const _keycloak = createKeycloak(keycloakConfig);
app.config.globalProperties.$keycloak = _keycloak;
await initKeycloak(keycloakInitOptions);
},
};
export { getToken, useKeycloak, vueKeycloak };
//# sourceMappingURL=index.mjs.map