Reactivity for root props in Vue when they are external JS classes

513 Views Asked by At

When creating an Vue (v3) application, you can start it by calling createApp with your main component in main.js file:

createApp({
      render () {
        return h(App, props)
      }
}

where App is your main component and props are root props you pass to your component. Until here everything is fine. The problem comes when using as a prop an external JS class. Even if you want to make it reactive, so you can detect changes in your root props, it won't work:

const props = reactive({ keycloak: keycloak })

How is it possible to make it work with a class root prop?

The particular problem I found it when using this guide https://www.keycloak.org/securing-apps/vue for integrating keycloack (OAuth2 Identity Provider) with a Vue application and I have problems with the reactivity of the token obtained.

As you can see in the code, there is a timer that calls a function that updates the object keycloak, but this changes are not being shown in the components of the application, they just keep the first value. Something I consider wrong as the whole point of this particular problem is having an update token to use in your components.

Note: the example is in Vue 2, but it is not working either with 2 or 3 version.

let initOptions = {
  url: 'http://127.0.0.1:8080/auth', realm: 'keycloak-demo', clientId: 'app-vue', onLoad: 'login-required'
}

let keycloak = Keycloak(initOptions);

keycloak.init({ onLoad: initOptions.onLoad }).then((auth) => {
  if (!auth) {
    window.location.reload();
  } else {
    Vue.$log.info("Authenticated");

    new Vue({
      el: '#app',
      render: h => h(App, { props: { keycloak: keycloak } })
    })
  }


//Token Refresh
  setInterval(() => {
    keycloak.updateToken(70).then((refreshed) => {
      if (refreshed) {
        Vue.$log.info('Token refreshed' + refreshed);
      } else {
        Vue.$log.warn('Token not refreshed, valid for '
          + Math.round(keycloak.tokenParsed.exp + keycloak.timeSkew - new Date().getTime() / 1000) + ' seconds');
      }
    }).catch(() => {
      Vue.$log.error('Failed to refresh token');
    });
  }, 6000)

}).catch(() => {
  Vue.$log.error("Authenticated Failed");
});
1

There are 1 best solutions below

1
On

my answer comes a bit later but you can try this in main.ts:


    import App from './App.vue'
    import Keycloak from "keycloak-js"
    
    const keycloakOptions = {
        url: 'http://localhost:8080/auth/',
        realm: 'myRealm',
        clientId: 'myClient',
        'public-client': true,
        'verify-token-audience': false
    }
    
    const keycloak = Keycloak(keycloakOptions)
    const appKcProps = reactive({ keycloak: keycloak })
    
    keycloak.init({onLoad: 'login-required'}).then((auth) => {
        if (!auth) {
          window.location.reload();
        } else {
          console.log("Authenticated");
        }  
      
        //Token Refresh
        setInterval(() => {
          keycloak.updateToken(70).then((refreshed) => {
            if (refreshed) {
                console.log('Token refreshed' + refreshed);
            } else {
                console.log('Token not refreshed, valid for ' + keycloak.tokenParsed?.exp  + ' seconds');
            }
          }).catch(() => {
            console.log('Failed to refresh token');
          });
        }, 6000)
      
      }).catch(() => {
        console.log("Authenticated Failed");
    })
    
    createApp({ 
            render(){
                return h(App, appKcProps)
            } 
        })
        .use(store)
        .use(router)