A user authentication system with Nuxt JS & Firebase Auth

A user authentication system with Nuxt JS & Firebase Auth

This is a piece of code from one of my ongoing projects which I’ve planned to keep in a different repository. So that, I can reuse the codebase whenever I need similar functionality in future projects.

Github Link: github.com/mi6crazyheart/nuxt-vuetify-fireb..

Different Component:

How to use:

Step 1:

  • Clone the repo & build the setup.
git clone https://github.com/mi6crazyheart/nuxt-vuetify-firebase-auth.git
cd nuxt-vuetify-firebase-auth
npm install

Step 2:

  • Create your Firebase project & enable the “Email/Password” Sign-in method from the Authentication section.

Screenshot 2021-10-16 at 6.16.24 PM.png

  • Generate the Firebase configuration details from the Project setting. Basically, you need the configuration details for the following things.
apiKey: '<apiKey>',
authDomain: '<authDomain>',
projectId: '<projectId>',
storageBucket: '<storageBucket>',
messagingSenderId: '<messagingSenderId>',
appId: '<appId>',
measurementId: '<measurementId>'

Step 3:

  • Add the Firebase configuration details in the “nuxt.config.js" file in the module section.
// Modules: https://go.nuxtjs.dev/config-modules
modules: [
// https://go.nuxtjs.dev/axios
'@nuxtjs/axios',
// https://go.nuxtjs.dev/pwa
'@nuxtjs/pwa',
[
  '@nuxtjs/firebase',
  {
    config: {
      apiKey: '<apiKey>',
      authDomain: '<authDomain>',
      projectId: '<projectId>',
      storageBucket: '<storageBucket>',
      messagingSenderId: '<messagingSenderId>',
      appId: '<appId>',
      measurementId: '<measurementId>'
    },
    services: {
      auth: {
        persistence: 'local', // default
        initialize: {
          onAuthStateChangedAction: 'onAuthStateChangedAction',
          subscribeManually: false
        },
        ssr: true
      }
    }
  }
]
],

Step 4:

  • That’s it. Now start the dev environment :)
npm run dev

Authentication functionality:

  • User Sign-in/Signout
  • Signup for the new user account with email-id verification
  • Forget Password

User Sign-in/Signout:

For sign-in using the following “login()” method. Inside “login()”, we are calling Firebase “signInWithEmailAndPassword” function with user’s email & password. On successful login, we are enabling the user’s auth state by calling the “onAuthStateChangedAction” method of Vuex State. After setting the user’s auth state data we are redirecting the user to the profile page.

File: /pages/signin.vue

login() {
  let formValidation = this.$refs.form.validate();

  if (formValidation) {
    this.$fire.auth
      .signInWithEmailAndPassword(this.email, this.password)
      .then((userCredential) => {
        const authUser = {
          uid: userCredential.user.uid,
          email: userCredential.user.email,
        };
        this.$store
          .dispatch("onAuthStateChangedAction", {
            authUser,
          })
          .then(() => {
            this.$router.replace("/profile");
          })
          .catch((error) => {
            console.log("User State error", error);
          });
      })
      .catch((error) => {
        console.log("Login error", error);
        this.snackbar = true;
        this.errorMessage = error.message;
      });
  }
},

In the case of user Signout, we are calling the “logout” method from the profile page & redirect the user to the landing page.

File: /pages/profile.vue

async logout() {
  await this.$fire.auth.signOut();
  this.$router.replace("/");
},

Signup for the new user account with email-id verification:

In Signup, we are calling our “createAccount” method where we use Firebase “createUserWithEmailAndPassword” function with the user’s email-id & password. On successful creation of user’s account, we are calling Firebase “sendEmailVerification” method for sending an email verification link to their given email id. After that setting user’s display name & auth state then redirecting the user to the profile page.

Files: /auth/signup.vue

createAccount() {
      let formValidation = this.$refs.form.validate();

      if (formValidation) {
        this.$fire.auth
          .createUserWithEmailAndPassword(this.email, this.password)
          .then((userCredential) => {
            this.$fire.auth.currentUser
              .sendEmailVerification()
              .then(() => {
                // Email verification sent!
                // ...
              })
              .catch((error) => {
                console.log(
                  "Caught error in sending email verification link to user",
                  error
                );
              });

            const currentUser = this.$fire.auth.currentUser;
            currentUser
              .updateProfile({
                displayName: this.name,
                // photoURL: "https://example.com/jane-q-user/profile.jpg",
              })
              .then(() => {
                // Update successful
                // ...
              })
              .catch((error) => {
                console.log("update user profile error", error);
              });

            const authUser = {
              uid: userCredential.user.uid,
              email: userCredential.user.email,
            };
            this.$store
              .dispatch("onAuthStateChangedAction", {
                authUser,
              })
              .then(() => {
                this.$router.replace("/member/desk");
              })
              .catch((error) => {
                console.log("User State error", error);
              });
          })
          .catch((error) => {
            console.log("Signup error", error);
            this.snackbar = true;
            this.errorMessage = error.message;
          });
      }
    },

Forget Password:

In this case, we are using our “resetPassword” method. Inside which we are calling Firebase “sendPasswordResetEmail” with user email id to send a password reset link to their given email address.

File: /auth/resetpassword

resetPassword() {
      let formValidation = this.$refs.form.validate();

      if (formValidation) {
        this.$fire.auth
          .sendPasswordResetEmail(this.email)
          .then(() => {
            this.snackbarSuccess = true;
            this.successMessage =
              "Reset Password link sent to your email address. Please check your inbox";
          })
          .catch((error) => {
            console.log("Reset Password error", error);
            this.snackbar = true;
            this.errorMessage = error.message;
          });
      }
    },

Besides these, there are two more places where you may need to make changes according to your need.

  • Middleware
  • Vuex State

Middleware: In the middleware folder currently there is one file “auth.js” where we’ve kept certain logic to redirect different pages depending upon the user’s session information.

export default function ({ store, app, route, redirect }) {
    const user = store.state.user;
    console.log('from middleware', user)

    if (route.path === '/auth/signin' || route.path === '/' || route.path === '') {
        if (user) {
            return redirect('/profile')
        }
    }

    if (route.path !== '/auth/signin' && route.path !== '/auth/signup' && route.path !== '/auth/resetpassword' && route.path !== '/' && route.path !== '') {
        if (!user) {
            return redirect('/auth/session')
        }
    }

}

Vuex State: This is related to our “store” folder which has our “index.js” file. This file has all the user’s auth management codes.


const actions = {
    async onAuthStateChangedAction(state, { authUser, claims }) {
        console.log('onAuthStateChangedAction - authUser', authUser);

        if (!authUser) {
            state.commit('SET_USER', null)
        } else {
            const { uid, email } = authUser
            state.commit('SET_USER', {
                uid,
                email,
            });
        }
    },

    async nuxtServerInit({ dispatch, commit }, { res }) {
        if (res && res.locals && res.locals.user) {
            const { allClaims: claims, idToken: token, ...authUser } = res.locals.user
            console.log('nuxtServerInit - authUser', authUser);
            const { uid, email } = authUser

            await dispatch('onAuthStateChangedAction', {
                authUser,
                claims,
                token
            });
        }
    }
}

const mutations = {
    SET_USER(state, user) {
        state.user = user
    },
}

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

const getters = {
    getUser(state) {
        return state.user
    },
    isLoggedIn(state) {
        let userLoggedIn = false
        if (state.user) {
            userLoggedIn = true
        }
        return userLoggedIn
    }
}

export default {
    state,
    actions,
    mutations,
    getters,
}

That’s it. I think this much is sufficient to use this boilerplate code in your project. Let me know if you’ve any more doubt or questions. I’ll definitely try to clear that out.