Categories
Nuxt.js

Adding Authentication to a Nuxt App with the Firebase

Spread the love

With the Nuxt Auth module, we can add authentication to our Nuxt app with ease.

One way is to add authentication with Firebase.

In this article, we’ll look at how to add Firebase authentication to our server-side rendered Nuxt app.

Install Packages

We have to add some packages to add Firebase to our Nuxt app.

To do that, we run:

npm i @nuxtjs/firebase @nuxtjs/pwa firebase firebase-admin

to add the required packages.

Configuration

We have to add configuration to our Nuxt app so that we can get the user when we load pages.

In nuxt.config.js , we write:

export default {
  /*
  ** Nuxt rendering mode
  ** See https://nuxtjs.org/api/configuration-mode
  */
  mode: 'universal',
  /*
  ** Nuxt target
  ** See https://nuxtjs.org/api/configuration-target
  */
  target: 'server',
  /*
  ** Headers of the page
  ** See https://nuxtjs.org/api/configuration-head
  */
  head: {
    title: process.env.npm_package_name || '',
    meta: [
      { charset: 'utf-8' },
      { name: 'viewport', content: 'width=device-width, initial-scale=1' },
      { hid: 'description', name: 'description', content: process.env.npm_package_description || '' }
    ],
    link: [
      { rel: 'icon', type: 'image/x-icon', href: '/favicon.ico' }
    ]
  },
  /*
  ** Global CSS
  */
  css: [
  ],
  /*
  ** Plugins to load before mounting the App
  ** https://nuxtjs.org/guide/plugins
  */
  plugins: [
  ],
  /*
  ** Auto import components
  ** See https://nuxtjs.org/api/configuration-components
  */
  components: true,
  /*
  ** Nuxt.js dev-modules
  */
  buildModules: [
  ],
  /*
  ** Nuxt.js modules
  */
  modules: [
    // Doc: https://axios.nuxtjs.org/usage
    '@nuxtjs/axios',
    '@nuxtjs/pwa',
    [
      '@nuxtjs/firebase',
      {
        config: {
          apiKey: "api-key",
          authDomain: "project-id.firebaseapp.com",
          databaseURL: "https://project-id.firebaseio.com",
          projectId: "project-id",
          storageBucket: "project-id.appspot.com",
          messagingSenderId: 'message-sender-id',
          appId: "BookDb"
        },
        services: {
          auth: {
            persistence: 'local',
            initialize: {
              onAuthStateChangedMutation: "SET_USER",
              onAuthStateChangedAction: 'onAuthStateChangedAction',
            },
            ssr: {
              serverLogin: {
                sessionLifetime: 60 * 60 * 1000,
                loginDelay: 50
              }
            }
          }
        }
      }
    ]
  ],
  /*
  ** Axios module configuration
  ** See https://axios.nuxtjs.org/options
  */
  axios: {

},
  /*
  ** Build configuration
  ** See https://nuxtjs.org/api/configuration-build/
  */
  build: {
  },
  firebase: {
    services: {
      auth: {
        ssr: true
      }
    }
  },
  pwa: {
    meta: false,
    icon: false,
    workbox: {
      importScripts: [
        '/firebase-auth-sw.js'
      ],
      dev: true
    }
  }
}

We add the @nuxtjs/firebase module with many options.

The config property has the Firebase configuration options.

services configures the auth service to persist the user.

The onAuthStateChangeMutation action is the Vuex action to save the authenticated user’s data.

ssr has the options for how long to keep the user data.

The sessionLifetime property has the session lifetime.

And loginDelay is the delay to save the user data after a successful login.

Vuex Store

We’ve to create a Vuex store to store the data.

To do that, we create a store/index.js file and write:

export const state = () => ({
  authUser: {}
})

export const actions = {
  async onAuthStateChangedAction({ commit }, { authUser, claims }) {
    const { uid, email, emailVerified, displayName, photoURL } = authUser

  commit('SET_USER', {
      uid,
      email,
      emailVerified,
      displayName,
      photoURL,
      isAdmin: claims.custom_claim
    })
  },
  async nuxtServerInit({ dispatch, commit }, { res }) {
    console.log(res.locals)
    if (res && res.locals && res.locals.user) {
      const { allClaims: claims, idToken: token, ...authUser } = res.locals.user
      await dispatch('onAuthStateChangedAction', {
        authUser,
        claims,
        token
      })
      commit('ON_AUTH_STATE_CHANGED_MUTATION', { authUser, claims, token })
    }
  }
}

export const mutations = {
  ON_AUTH_STATE_CHANGED_MUTATION(state, { authUser, claims }) {
    const { uid, email, emailVerified, displayName, photoURL } = authUser

    state.authUser = {
      uid,
      displayName,
      email,
      emailVerified,
      photoURL: photoURL || null,
      isAdmin: claims.custom_claim
    }
  },
  SET_USER(state, payload) {
    console.log(payload)
    state.authUser = payload;
  }
}

The onAuthStateChanged action is invoked by nuxtServerInit to set the authenticated user’s data on page load.

nuxtServerInit is run when the page loads.

ON_AUTH_STATE_CHANGED_MUTATION is a mutation to save the authUser state.

SET_USER sets the authUser state.

When we run the this.$fireAuth.signInWithEmailAndPassword method is run successful by authentication with the correct credentials, then the actions and mutations will be run.

The res.locals.user property in the nuxtServerInit will also be set so that we have the currently logged in user’s data on page load.

Login Form

Finally, we need a login form so we can log in.

We create a login.vue file and add:

<template>
  <div class="container">
    <form @submit="signIn">
      <div>
        <label>Username</label>
        <input type="text" v-model="login.email" />
      </div>
      <div>
        <label>Password</label>
        <input type="text" v-model="login.password" />
      </div>
      <div>
        <button type="submit">Submit</button>
      </div>
    </form>
  </div>
</template>

<script>
export default {
  data() {
    return {
      login: {},
    };
  },
  methods: {
    async signIn() {
      try {
        const { email, password } = this.login;
        await this.$fireAuth.signInWithEmailAndPassword(email, password);
      } catch (error) {
        console.log(error);
      }
    },
  },
};
</script>

We create a login form and if we log in with the right email and password, the Vuex actions will be run to set the data.

This is because the static/assets/firebase-auth-sw.js service worker that comes with the Nuxt Firebase does that work for us in the background.

By John Au-Yeung

Web developer specializing in React, Vue, and front end development.

Leave a Reply

Your email address will not be published. Required fields are marked *