Nuxt Guard/Protect User and Admin Pages Using Middleware and Firebase Authentication

November 18, 2020

Firebase Authentication

Setup Firebase Authentication With Nuxt.js.

I will use Custom Claims to setup admin flags.

  • Authenticated user can access /console
  • Only admin can access /admin

Edit store/index.js (Vuex Store) to add support for custom claims

export const state = () => ({
  user: null
})

export const mutations = {
  ON_AUTH_STATE_CHANGED_MUTATION: async (state, { authUser, claims }) => {
    if (authUser) {
      state.user = {
        uid: authUser.uid,
        // email: authUser.email,
        displayName: authUser.displayName,
        admin: claims.admin
      }

      /*
      const idTokenResult = await authUser.getIdTokenResult()
      if (!!idTokenResult.claims.active) {
        state.user.active = true
      }
      else {
        state.user.active = false
      }
       */
    }
    else {
      state.user = null
    }
  }
}

How to you assign admin provilege to a specific user? Depending on your use case, you could use a cloud functions or cli.

Using Node.js

await admin.auth().setCustomUserClaims(uid, {admin: true})

NOTE: Refer Firebase Admin Setup

Using Python

auth.set_custom_user_claims(uid, {'admin': True})

Guard Pages

We use nuxt middleware to protect pages like /console (authenticated user only) and /admin (admin only)

Edit nuxt.config.js

export default {
  router: {
    middleware: 'router-auth'
  },
}

Edit middleware/router-auth.js

export default function({ store, redirect, error, route }) {
  // console.log('user', store.state.user)
  if (!isAuthenticated(store.state.user) && requireAuthentication(route))
    redirect('/') // /login
  else if (!isAdmin(store.state.user) && requireAdmin(route))
    // redirect('/error_admin_only')
    // redirect('/error', { code: 'require_admin' })
    error({
      statusCode: 401,
      message: 'Only Admin is allowed to access this page'
    })    
}

function isAuthenticated(user) {
  return user
}

function requireAuthentication(route) {
  // return !['/', '/about', '/login'].includes(route.path) // || !route.path.startswith('/error_')
  return ['/console'].includes(route.path)
}

function isAdmin(user) {
  return user && user.admin
}

function requireAdmin(route) {
  return ['/admin'].includes(route.path)
}

Edit pages/console.vue

<template>
  <h1>Console</h1>
</template>

Edit pages/admin.vue

<template>
  <h1>Admin</h1>
</template>
This work is licensed under a
Creative Commons Attribution-NonCommercial 4.0 International License.