No More Posting New Topics!

If you have a question or an issue, please start a thread in our Github Discussions Forum.
This forum is closed for new threads/ topics.

Navigation

    Quasar Framework

    • Login
    • Search
    • Categories
    • Recent
    • Tags
    • Popular
    • Users
    • Groups
    • Search

    Axios interceptor and router push not working

    Help
    7
    8
    7235
    Loading More Posts
    • Oldest to Newest
    • Newest to Oldest
    • Most Votes
    Reply
    • Reply as topic
    Log in to reply
    This topic has been deleted. Only users with topic management privileges can see it.
    • D
      darkshifty last edited by darkshifty

      I am trying to push users back to the login page if authentication fails. However in a Axios interceptor the router push doesn’t seem to work. Are there good any other ways that i can deal with a authentication fail?

      import Vue from 'vue'
      import axios from 'axios'
      import store from '../store';
      
      // request interceptor
      axios.interceptors.request.use(
          config => {
              const token = store().getters['auth/accessToken'];
              if (token) {
                  config.headers['Authorization'] = 'Bearer ' + token;
              }
              return config;
          },
          error => {
              Promise.reject(error)
          });
      
      // response interceptor
      axios.interceptors.response.use((response) => {
              return response
          },
          function (error) {
      
              if (error.response.status === 401 && !window.refreshing) {
                  window.refreshing = true;
                  return axios.post('http://posadmin/api/auth/refresh',
                      {
                          "refresh_token": store().getters['auth/refreshToken']
                      })
                      .then(res => {
                          console.log(res.status);
                          console.log(res.data);
                          if (res.status === 200) {
                              store().commit("auth/refreshToken", res.data);
                              axios.defaults.headers.common['Authorization'] = 'Bearer ' + store().getters['auth/accessToken'];
      
                              return axios(error.config);
                          } else {
                              console.log('200 else');
                              store().dispatch("auth/setLogout");
                              this.$router.push('/login');
                          }
                      })
                      .catch((error) => {
                          console.log(window.refreshing);
                          console.log('catch '+error);
                          store().dispatch("auth/setLogout");
                          this.$router.push('/login');
                      });
              }
      
              // return Error object with Promise
              return Promise.reject(error);
          });
      
      Vue.prototype.$axios = axios;
      
      
      
      1 Reply Last reply Reply Quote 1
      • J
        jraez last edited by

        You can simply use window.location = '/#/login'

        1 Reply Last reply Reply Quote 0
        • C
          chyde90 last edited by

          Does it work? What @jraez said should help.

          If you really want to use the router, you can do that, too.
          The code you showed is in a boot file, right? So I think your this.$router.push('/login') call doesn’t work because this.$router is not defined. Normally, you write that in a Vue component, where this refers to the component - but you are in a boot file.

          This is how you can do it:

          import axios from "axios"
          
          export default ({ Vue, router }) => { // <-------- This is where the `router` comes from
            Vue.prototype.$axios = axios;
          
            // ... (your request interceptor here)
          
            axios.interceptors.response.use(response => {
              return response;
            }, error => {
              if (error.response.status === 401) {
                // ...
                router.push("/login"); // <----  note there is no `this`
              }
              // ...
            });
          }
          
          1 Reply Last reply Reply Quote 1
          • M
            mdcode224 last edited by mdcode224

            Quick note: Vue warn again calling VueX methods such as dispatch or commit outside of a Vue component. Example:

             store().commit("auth/refreshToken", res.data);
            
            1 Reply Last reply Reply Quote 1
            • M
              mflorindo last edited by

              Hello!
              Were you able to make router.push work?
              I can’t seem to get it to work. 😞

              ‘’’
              import Vue from ‘vue’
              import axios from ‘axios’
              import { Notify } from ‘quasar’
              import router from ‘…/router’

              const axiosInstance = axios.create({
              baseURL: process.env.API
              })

              axiosInstance.interceptors.response.use(response => {
              return response
              }, error => {
              if (error.response.status === 401) {
              Notify.create({
              type: ‘negative’,
              timeout: 1000,
              position: ‘top’,
              message: error.response.data.message
              })
              router.push(’/login’)
              return Promise.reject(error)
              }
              })

              Vue.prototype.$axios = axiosInstance
              export { axiosInstance }

              ‘’’

              metalsadman 1 Reply Last reply Reply Quote 0
              • metalsadman
                metalsadman @mflorindo last edited by

                @mflorindo router is passed as an argument inside your bootfile https://quasar.dev/quasar-cli/boot-files#Anatomy-of-a-boot-file. or you can expose it from your src/router/index.js file. like this

                let router = null
                export default function ({ store }) {
                  router = new VueRouter({ ... })
                  ...
                  return router
                }
                
                export { router }
                
                //somefile.js then you can import it
                import { router } from '…/router’
                
                1 Reply Last reply Reply Quote 0
                • I
                  ilabutk last edited by

                  BTW, router.push({ name: 'dashboard' }) will throw a promise error but this will pass:

                        router.push({
                            path: '/dashboard'
                          }, () => { })
                  
                  1 Reply Last reply Reply Quote 0
                  • D
                    darkshifty last edited by darkshifty

                    Sorry for coming back very late to this topic, however the router intercept is very sensitive. Using window.location, dispatching/committing data in vuex or any other logics in the intercept are all very inconsistent. The users were experiencing different data in their localstorage than in their browser. I ended up with the following.

                    import VueRouter from 'vue-router'
                    import routes from './routes'
                    import store from 'src/store'
                    
                    const router = new VueRouter({
                        // This will make the page scroll to top for all route navigations.
                        scrollBehavior: () => ({x: 0, y: 0}),
                        routes,
                        mode: process.env.VUE_ROUTER_MODE,
                        base: process.env.VUE_ROUTER_BASE
                    });
                    
                    const routingServiceChecks = async (to, from, next) => {
                        const requiresAuth = to.matched.some(route => route.meta.requiresAuth);
                        const accessToken = store().getters['auth/accessToken'];
                    
                        // authenticated check
                        if (requiresAuth && accessToken === null) {
                            return next('/login');
                        }
                        // always go to the next route
                        next();
                    };
                    
                    router.beforeEach(routingServiceChecks);
                    
                    export default router
                    

                    I moved all other logics to the base layout or other components. I made a separate service which I catch seperately once the data retrieval is initiated and fails. Refreshing tokens I moved to a global function which is initiated on a failure of retrieving any data, persisting the new tokens to the localstorage after that has been 100% successful.

                    here is an example of my login function and refresh without the use of interception:

                    async onSubmit() {
                        await this.$store.dispatch('instance/loading', true);
                        if (this.$v.$invalid) {
                            await this.$store.dispatch('instance/loginFailed', this.$t('login.empty'));
                        } else {
                            await this.$auth.login(this.login).then(response => {
                                if (response.status === 200) {
                                    this.$store.dispatch('auth/loginSuccess', response.data).then(() => {
                                        if(this.redirect !== '') {
                                            router.push({name: this.redirect}, onComplete => {}, onAbort => {})
                                        } else {
                                            router.push({name: 'home'}, onComplete => {}, onAbort => {})
                                        }
                                    });
                                } else {
                                    this.$store.dispatch('instance/loginFailed', this.$t('text.login.failed'))
                                }
                            }).catch(error => {
                                this.$store.dispatch('instance/loginFailed',
                                    this.$t('text.' + Mixins.error('login', error.response.status))
                                );
                            })
                        }
                        await this.$store.dispatch('instance/loading', false);
                    }
                    
                    attemptRefresh (type) {
                        this.$auth.refresh().then(response => {
                            // set refresh to success
                            this.$store.dispatch('auth/setRefreshSuccess', response.data).then(() => {
                                switch (type) {
                                    case 'core':
                                        this.core()
                                        break;
                                    case 'sync':
                                        this.sync()
                                        break;
                                }
                            })
                        }).catch(() => {
                            this.setError(false, true)
                        })
                    }
                    
                    1 Reply Last reply Reply Quote 0
                    • First post
                      Last post