4

I'm stuck with this since awhile. I want to access my keycloak instance from within the vue router.js file.

const preventRoutes = {
  beforeEnter: (to, from, next) => {
    console.log(App.$keycloak.authenticated); //here. (Undefined)
    if (store.getters.getLoginState === "true") {
      ...
    } else {
      ...
    }
  }
}

access vue 3 app instance api from non-vue fiile

I'm trying this solution. As it's the only VUE3 I can find, but still, I think he skipped some steps. Can someone simplify please?

Adviced Solution

const preventRoutes = {
  beforeRouteEnter(to, from, next) {
    next(vm => {
      // access to component instance via `vm`
      // console.log(vm.$keycloak.authenticated);
      if (this.vm.$keycloak.authenticated) {
        next();
      } else {
        next("/");
      }
    })
  }
}

main.js

const myApp = createApp(App)

let initOptions = {
  url: KeycloakConfig["auth-server-url"], realm: KeycloakConfig.realm, clientId: KeycloakConfig.resource, clientSecret: KeycloakConfig.credentials.secret
}

const keycloak = Keycloak(initOptions)

myApp.config.globalProperties.$keycloak = keycloak;
myApp.use(VueAxios, axios)
myApp.use(store)
myApp.use(router)
myApp.mount("#app");

keycloak.init({
  onLoad: "check-sso",

  checkLoginIframe: false
}).then(async (auth) => {
  if (!auth) {

  } else if (auth) {
    router.push("/dashboard"); 
  }
}).catch((e) => {
  console.log('Serwer lezy: ' + e)
})
0

5 Answers 5

2

I have another solution (maybe its more a workaround, but it feels kinda correct)

You could wrap your router inside a custom plugin install method, like:

const router = createRouter({
    history: createWebHashHistory(),
    routes,
});

export default {
    install(app, options) {
        router.install(app)

        router.beforeEach((to, from, next) => {
            // access all used plugins
            console.log(app.config.globalProperties.$store)
            console.log(app.config.globalProperties.$First)
            // ... stuff ...
        });
    },
};

In your main.js you can just use(...) the router like before:

import { createApp } from "vue";
import App from "./App.vue";
import router from "./router";
import store from "./store";
import * as plugins from "./plugins";

const app = createApp(App)

app.use(store)
   .use(plugins.First)
   .use(plugins.Second)
   .use(router, app) // add "app" as second param, that way you can access the store and every other plugin within the router
   .mount("#app");
Sign up to request clarification or add additional context in comments.

1 Comment

well. I changed the whole authentication method because of this issue. Anyway, thanks a lot maybe someone else would need it.
2

This worked for me:

//main.js
const app = createApp(App)
app.provide('app', app)

//router.js
router.beforeEach(function(to, from, next) {
  const app = inject('app');
  console.log(app.$keycloak.authenticated)
})

Comments

1

One solution is for router.js to export a function that captures a given app argument, which could be used either in a route's beforeEnter hook:

// router.js
import { createRouter as createVueRouter, createWebHistory } from 'vue-router'

const createRoutes = (app) => [
  {
    path: '/restricted',
    component: () => import('@/views/Restricted.vue'),
    beforeEnter(to, from, next) {
                             👇
      const authenticated = app.config.globalProperties.$keycloak?.authenticated
      if (authenticated) {
        next()
      } else {
        next('/login')
      }
    }
  },
  //...
]

export const createRouter = (app) => {
  return createVueRouter({
    history: createWebHistory(),
    routes: createRoutes(app), 👈
  })
}

demo 1

...or in the global beforeEach hook:

// router.js
import { createRouter as createVueRouter, createWebHistory } from 'vue-router'

const createRoutes = () => [
  {
    path: '/restricted',
    component: () => import('@/views/Restricted.vue'),
    meta: { requiresAuth: true }, 👈
  },
  //...
]

export const createRouter = (app) => {
  const router = createVueRouter({
    history: createWebHistory(),
    routes: createRoutes(),
  })

  router.beforeEach((to, from, next) => {
                          👇
    const authenticated = app.config.globalProperties.$keycloak?.authenticated
    if (to.meta.requiresAuth && !authenticated) {
      next({ name: 'Login' })
    } else {
      next()
    }
  })
  return router
}

demo 2

Then your main.js would use it like this:

import { createRouter } from './router'

const app = createApp(App)
const router = createRouter(app)
app.use(router)

const keycloak = /*...*/

keycloak.init(/*...*/)
  .then((auth) => {
    if (auth) {
      router.push('/dashboard')
    }
  })

app.mount('#app')

1 Comment

I really did man. Very precisely. I just forgot I undod this part before sharing it with you. codesandbox.io/s/affectionate-robinson-stc0n?file=/router.js Now it's giving me another error too. That createRouter can't be found in router.js. Anyway please if it's too much to ask you. You really tried to help ! Much appreciated.
0

The beforeEnter and the beforeRouteEnter HAVE NO access to the Vue instance.

You can either change your logic to use beforeRouteLeave that HAS access to the instance using this or you can add a callback function like:

beforeRouteEnter (to, from, next) {
  next(vm => {
    // access to component instance via `vm`
    console.log(vm.$keycloak.authenticated);
  })
}

On your specific case I would change the logic to use the beforeRouteLeave and prevent the next() function to be called in case the user is not authenticated.

You can find this information in more details here: https://router.vuejs.org/guide/advanced/navigation-guards.html#in-component-guards

Comments

0

You can just append your route guard to your main.js file, which according to your code, becomes:

const myApp = createApp(App)

let initOptions = {...}

const keycloak = Keycloak(initOptions)

myApp.config.globalProperties.$keycloak = keycloak;
myApp.use(VueAxios, axios)
myApp.use(store)
myApp.use(router)
myApp.mount("#app");

keycloak.init({...}).then(async (auth) => {
  if (auth) {
    router.push("/dashboard"); 
  }
}).catch((e) => {...})

router.beforeEnter: (to, from, next) => {
  console.log(myapp.$keycloak.authenticated); //here. (Undefined)
  if (store.getters.getLoginState === "true") {
    ...
  } else {
    ...
  }
}

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.