Pattern For Redirecting On Unauthorized Vuex Actions

- 1 answer

Navigation guards are perfect for redirecting unauthorized users to a login page, but what does one do to redirect unauthorized vuex actions to a login page?

I can do this easily enough in the vue method where I'm calling the action like so:

  if (!this.isLoggedIn) {
    this.$router.push({ name: 'login', query: { comeBack: true } })

But then I'm inserting these 5 lines of code for every component method that requires authorization.

All the solutions I can think of sound hacky, so I'm wondering what the vuex way is:

  1. In order to reject it at the vuex action level, I have to pass up the $router instance, and I'm still reusing the 5 lines for each action that requires auth.

  2. I can handle this in a utility file, but then I'm handling $router instance in that file.

  3. I can use a global vue mixin and call it (a) before making a call and then again (b) when getting a 401 back from the server.

All those seem odd. What vuex way am I missing here?



This sounds like a job for middleware. Unfortunately, Vuex doesn't have an official way to do middleware.

There is a subscribeAction() but that runs after the commit, so does not allow mods to the action. There is also a proposal Middleware processing between actions and mutation.

As I see it, we want middleware to be able to do two generic things

  • cancel the action
  • allow alternative actions to be called

The second is difficult to do without patching store.dispatch() or messing with the private property _actions after store has been created.

However, to guard an action as you describe, we only need to be able to cancel it.

Here is a poor-man's middleware for the modules pattern for Vuex store which I prefer.

store construction from modules

export const store = new Vuex.Store({
  modules: {
    pages: applyMiddleware(pages),


const applyMiddleware = function(module) {
  if(module.middlewares) {
    Object.values(module.middlewares).forEach(middlewareFn => {
      Object.keys(module.actions).forEach(actionName => {
        const actionFn = module.actions[actionName]
        module.actions[actionName] = addMiddleware(actionName, actionFn, middlewareFn)
  return module;


const addMiddleware = function(actionName, actionFn, middlewareFn) {
  return function(context, payload) {
    const resultFn = middlewareFn(actionFn)
    if(resultFn) {
      resultFn(context, payload)

defining middleware in the module

const actions = {
  myAction: (context, payload) => {
    context.commit('THE_ACTION', payload)

const middlewares = {
  checkAuthMiddleware: (action) => {
    return this.isLoggedIn 
      ? action // if logged-in run this action
      : null;  // otherwise cancel it

export default {

This implementation has module-specific middleware functions, but you could also define them globally and apply to as many modules as applicable.