2

Im trying to create a plugin for manage the Oauth2 token data in my vuejs app.

I created the plugin following some few tutorials that are available on the internet.

var plugin = {}

plugin.install = function (Vue, options) {
  var authStorage = {
    getToken () {
      let token = localStorage.getItem('access_token')
      let expiration = localStorage.getItem('expiration')
      if (!token || !expiration) {
        return null
      }
      if (Date.now() > parseInt(expiration)) {
        this.destroyToken()
        return null
      }

      return token
    },
    setToken (accessToken, expiration, refreshToken) {
      localStorage.setItem('access_token', accessToken)
      localStorage.setItem('expiration', expiration + Date.now())
      localStorage.setItem('refresh_token', refreshToken)
    },
    destroyToken () {
      localStorage.removeItem('access_token')
      localStorage.removeItem('expiration')
      localStorage.removeItem('refresh_token')
    },
    isAuthenticated () {
      if (this.getToken()) {
        return true
      } else {
        return false
      }
    }
  }

  Vue.prototype.$authStorage = authStorage
}

export default plugin

but when a try to access the methods on the main.js file, i get error saying that the object is undefined.

import Vue from 'vue'
import App from './App'
import router from './router'
import AuthStorage from './AuthStorage.js'

Vue.config.productionTip = false
Vue.use(AuthStorage)

router.beforeEach((to, from, next) => {
  if (to.matched.some(record => record.meta.requireAuth)) {
    if (!Vue.$authStorage.getToken()) {
      next({
        path: '/',
        query: { redirect: to.fullPath }
      })
    } else {
      next()
    }
  } else {
    next()
  }
})
axios.defaults.headers.common = {
  'Authorization': `Bearer ${Vue.$authStorage.getToken()}`
}
/* eslint-disable no-new */
new Vue({
  el: '#app',
  router,
  template: '<App/>',
  components: { App }
})

chrome console showing the error

Inside the components the plugin works as expected. The problem is when o try to use in the main.js file. I already tried with: this.$authStorage this.authStorage Vue.authStorage

no success

1 Answers1

5

You are adding $authStorage to the prototype of Vue.

Vue.prototype.$authStorage = authStorage

That means will only be available on instances of the Vue object (ie. the result of new Vue(...).

If you want $authStorage to be available as a property of Vue without creating an instance, you need to add it as a static property.

Vue.$authStorage = authStorage

But, if it were me, I would probably take a different approach. I would likely build the AuthStorage plugin like this:

const authStorage = {
    getToken() {
      let token = localStorage.getItem('access_token')
      let expiration = localStorage.getItem('expiration')
      if (!token || !expiration) {
        return null
      }
      if (Date.now() > parseInt(expiration)) {
        this.destroyToken()
        return null
      }

      return token
    },
    setToken(accessToken, expiration, refreshToken) {
      localStorage.setItem('access_token', accessToken)
      localStorage.setItem('expiration', expiration + Date.now())
      localStorage.setItem('refresh_token', refreshToken)
    },
    destroyToken() {
      localStorage.removeItem('access_token')
      localStorage.removeItem('expiration')
      localStorage.removeItem('refresh_token')
    },
    isAuthenticated() {
      if (this.getToken()) {
        return true
      } else {
        return false
      }
    },
    install(Vue) {
      Vue.prototype.$authStorage = this
    }
}

export default authStorage

Which would allow me to use it like this outside of Vue,

import Vue from 'vue'
import App from './App'
import router from './router'
import AuthStorage from './AuthStorage.js'

Vue.config.productionTip = false
Vue.use(AuthStorage)

router.beforeEach((to, from, next) => {
  if (to.matched.some(record => record.meta.requireAuth)) {
    if (!AuthStorage.getToken()) {
      next({
        path: '/',
        query: { redirect: to.fullPath }
      })
    } else {
      next()
    }
  } else {
    next()
  }
})

And reference it like this inside of Vue:

created(){
  let token = this.$authStorage.getToken()
}

Here is an example.

Bert
  • 80,741
  • 17
  • 199
  • 164