As a web developer, you know that authentication is a big part of front end development. You also know that using a state manager can be a huge help when you’re creating a Vue app.

Traditionally Vue apps have used Vuex in order to manage state. This tool was the equivalent of Redux in the React ecosystem, or the native services in Angular. However, this solution was too complex for many small projects, and even for some bigger ones. That’s one of the main reasons why Pinia (sometimes called “the new Vuex”) has risen in popularity in recent time.

In this blog post, we’ll show you how to use Pinia with Vue to set up authentication in your app, one of the most common use cases for a state manager. Let’s get started!

Why would you need a state manager for authentication?

When you’re dealing with authentication, there are usually two things that you need to keep track of: the user’s credentials (usually in the form of a username and password) and the user’s session.

A state manager can help you with both of these tasks. For example, Vuex lets you define “getters”, which are functions that allow you to access parts of the state. So, you could create a getter for the user’s credentials, and another one for the user’s session.

Another thing that a state manager can do is help you with fetching data from an API. For example, if you’re using Vue with a backend framework like Laravel, you can use the Fetch API to make HTTP requests. Then, you can use a state manager to store the data that you get back from the API in a centralized place. This is important because it lets you easily access the data that you need from any component in your app.

So, how do you use Pinia with Vue to create an authentication process? Let’s take a look at the steps.

Setting up authentication in Vue with Pinia

1- Install Pinia in your project

First, you need to create a new instance of the Pinia state manager. In order to do this, you need to run the following command in your terminal, in a folder where you already have a Vue project setup:

npm i pinia

Then you need to create a new instance of Pinia globally in your project. For that, go to your main.js file and add the following code:

import { createApp } from "vue";
import "./index.css";
import App from "./App.vue";
import { createPinia } from "pinia";

const pinia = createPinia();

createApp(App).use(pinia).mount("#app");

This will allow you to use Pinia globally in all your app. Keep in mind, though, that this syntax is only valid if you’re using Vue 3.

2- Create a new store

Once you have created a new instance of Pinia, you need to create a new store. A store is simply a JavaScript object that contains the data that you want to have available globally in your app. In this case, we’ll call it user.js, and it will have the following structure:

// /store/user.js

import { defineStore } from "pinia";

export const useUserStore = defineStore("user", {
  state: () => ({
    user: null,
  }),

  actions: {
    async fetchUser() {
      const res = await fetch("https://localhost:3000/user");

      const user = await res.json();
      this.user = user;
    },
    async signUp(email, password) {
      const res = await fetch("https://localhost:3000/register", {
        method: "POST",
        headers: {
          "Content-Type": "application/json",
        },
        body: JSON.stringify({ email, password }),
      });
      const user = await res.json()
      this.user = user;
    },
    async signIn(email, password) {
      const res = await fetch("https://localhost:3000/register", {
        method: "POST",
        headers: {
          "Content-Type": "application/json",
        },
        body: JSON.stringify({ email, password }),
      });
      const user = await res.json();
      this.user = user;
    },
  },
});

In this store you’ll handle all the API calls that are related with authentication. We’ll also store all the user data here. That way, you can easily access it from any component in your app.

In this case, for example, we’re expecting to receive a “user” object from our backend and will store it globally in our Pinia store. That way, we can later check if a user is logged in or not, and add some security measures like a router guard.

3- Create a Login component

Once you have created your store, you need to implement it in your front end! In order to do that, one of the first things you’ll need is to create a login form in your Vue app. This form will take the username and password from the user and submit it to your API for authentication via our userStore. The form should look something like this:

<template>
  <form @submit.prevent="login">
    <label>Email</label>
    <input type="text" v-model="email" />
    <label>Password</label>
    <input type="password" v-model="password" />
    <button type="submit">Login</button>
  </form>
</template>

4- Connect your component with your Auth store

In your script section, you need to add some code to handle the form submission and call your login method. First, you’ll need to take advantage of the setup() method in order to give the component global access to our userStore:

<script>
import { useUserStore } from "../store/user";
export default {
  setup() {
    const userStore = useUserStore();
    return { userStore };
  },
};
</script>

Once you’ve done that, you’ll be able to access the methods and data you’ve used in your store from your component. For example, now you can create a login() method, and use it to call the signUp() method we created earlier in our Pinia store:

data() {
    return {
      email: "",
      password: "",
    };
  },
  methods: {
    async login() {
      await this.userStore.signIn(this.email, this.password);
    },
  },

This would be the final version of our Login.vue component:

<template>
  <form @submit.prevent="login">
    <label>Email</label>
    <input type="email" v-model="email" />
    <label>Password</label>
    <input type="password" v-model="password" />
    <button type="submit">Login</button>
  </form>
</template>

<script>
import { useUserStore } from "../store/user";
export default {
  setup() {
    const userStore = useUserStore();
    return { userStore };
  },
  data() {
    return {
      email: "",
      password: "",
    };
  },
  methods: {
    async login() {
      await this.userStore.signIn(this.email, this.password);
    },
  },
};
</script>

This would allow us to authenticate our user, and then we can access its properties directly from our template section. For example, if we had another page called Home.vue, we could pull the user data from our store and greet our user like this:

<template>
  <h2>Welcome, {{ userStore.user }}</h2>
</template>

<script>
import { useUserStore } from "../store/user";
export default {
  setup() {
    const userStore = useUserStore;
    return { userStore };
  },
};
</script>

That’s it! You’ve now set up authentication in your Vue app using Pinia. We hope that this blog post helped you learn how to use Pinia with Vue to set up authentication in your app. If you have any questions or if you run into any problems, feel free to reach out to us in the comments section below and we’ll be happy to help you out. Thanks for reading!

👋 Hey, I'm Alejandro Rodríguez
Hey there! I'm a front end developer from Spain and a web dev teacher at Ironhack. I've been writing for more than 7 years as a side project, and I love to mix both disciplines whenever I can. Besides working, I'm also passionate about travelling (often with my laptop as a digital nomad) and water sports. What could be better than writing about code in a Caribbean beach, or from a coworking space in an european city?

💬 Leave a comment

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

We will never share your email with anyone else.