Setting Up a Secure Authentication System in Vue.js

Setting Up a Secure Authentication System in Vue.js

When building web applications, one of the most important aspects to consider is authentication. Authentication ensures that only authorized users can access certain parts of your application, providing a layer of security for sensitive data and functionalities.

In simple terms, authentication is the process of verifying who a user is—typically by having them log in with a username and password. Once authenticated, users can access features and resources specific to them.

In this article, we’ll walk through the steps to create a basic authentication system in Vue.js. By the end, you’ll understand how to:

• Set up an authentication service to manage login and logout requests.

• Use Vuex (state management) to keep track of the user’s login status.

• Secure routes so that only logged-in users can access certain pages.

• Handle token expiration with token refresh logic, ensuring users stay logged in without interruptions.

Whether you’re building a simple app or a complex system, this guide will give you the foundation you need to secure your application.

Let’s dive in!


Step 1: Creating the Authentication Service

This step will focus on creating the authentication service to handle login and logout functionality.

Before we can start managing users and securing parts of our application, we need to create a service that handles the authentication process. This service will be responsible for sending login and logout requests to a backend API, and for storing the user’s authentication status in the browser.

What is an Authentication Service?

In simple terms, an authentication service is a piece of code that communicates with the backend server to:

Log users in by verifying their credentials (like username and password).

Log users out by clearing their session or token.

Store authentication data such as tokens (which allow the user to stay logged in).

Example: Setting up the Authentication Service

Let’s start by creating a service file called auth.service.js in your Vue.js project. This service will handle all interactions related to user authentication.

Here’s how you can structure it:

src/services/auth.service.js
src/services/auth.service.js

Explanation:

Axios: We’re using Axios to make HTTP requests to the backend API. This is how the app sends login credentials (like the username and password) to the server for verification.

login(): This method sends a POST request to the API with the user’s login credentials. If the login is successful, the server responds with an access token. This token is stored in the browser’s localStorage, allowing the app to remember the user is logged in.

logout(): When the user logs out, we simply remove the token from localStorage, which clears the login state.

Why do we store the token?

When the user logs in, the server gives us an access token, which is like a pass that allows the user to access certain parts of the app. By storing this token in localStorage, we can remember the user even if they refresh the page. This token will later be used to verify the user’s identity on every request they make.

Now that we’ve set up the authentication service, we’re ready to move on to the next step: managing the user’s login state using Vuex.


Step 2: Managing Authentication State with Vuex

This step will focus on manage the user’s login state using Vuex. This step will ensure that the application keeps track of whether the user is logged in or logged out, and it will help manage user data across different components.

Now that we have an authentication service in place, we need a way to manage the user’s login state throughout the application. This is where Vuex comes into play. Vuex is a state management library for Vue.js that allows us to store and manage global state—things like whether the user is logged in or not.

Why Use Vuex?

When a user logs in, we want to share that information across various parts of the application. For example:

• We might want to display the user’s name in a navigation bar.

• We need to know if a user is logged in to decide whether they can access certain pages.

• We may need to handle automatic logout if the user logs out from any page.

Vuex makes it easy to manage this global state in one place and share it across components.

Setting Up Vuex for Authentication

First, let’s create an auth module in Vuex that will handle our authentication logic.

1. Create a file called auth.module.js inside the store directory of your project.

Here’s an example of how we can set this up:

Article content

Explanation:

State: The state holds the current login status of the user. If the user is logged in, we retrieve their data from localStorage. Otherwise, the user is set to null.

Actions:

• login(): This action sends the login request via the AuthService and commits a mutation based on the result (success or failure).

• logout(): When called, this action logs the user out by clearing the token and updating the state.

Mutations:

• loginSuccess(): This mutation updates the state when the user successfully logs in.

• loginFailure(): If login fails, it ensures the user is marked as logged out.

• logout(): This mutation clears the state when the user logs out.

Using the Vuex Store

Now that we’ve set up the Vuex module for authentication, we can use it in our components. For example, in a login form, you would dispatch the login action like this:

Article content

This allows us to centralize the login/logout logic and easily control the authentication state throughout the entire application.

What’s Next?

Now that we’ve set up the Vuex store to manage authentication state, the next step is to protect specific routes in our application, ensuring that only logged-in users can access certain pages.


Step 3: Protecting Routes with Vue Router

Here we’ll focus on protecting routes in our application. This ensures that only authenticated users can access certain parts of the app, while unauthenticated users are redirected to the login page.

One of the most important parts of an authentication system is ensuring that only authorized users can access specific routes or pages. For example, you wouldn’t want someone who isn’t logged in to access the dashboard or other sensitive pages in your app.

In Vue.js, we use Vue Router to handle navigation between different pages of our app. We can also use it to protect routes by setting up navigation guards that check if a user is logged in before allowing them to access certain pages.

Setting Up Route Protection

To get started, we’ll modify our Vue Router configuration to include navigation guards.

1. Open the router/index.js file (or wherever you’ve configured your router).

2. Add a guard to check if a user is logged in before they can access specific routes.

Here’s an example of how to configure the router:

Article content

Explanation:

meta: { requiresAuth: true }: This adds a custom meta field to the route configuration, indicating that the route requires authentication. You can add this to any route you want to protect.

beforeEach(): This is a navigation guard that runs before every route change. It checks if the target route has the requiresAuth meta field and whether the user is logged in.

Redirect to Login: If the user is not logged in and tries to access a protected route, they’ll be redirected to the login page.

Protecting Multiple Routes

You can protect any number of routes by adding the meta: { requiresAuth: true } field to them. For example, if you have a dashboard route and a profile route that should only be accessible to logged-in users, you can set them up like this:

Article content

What Happens After Login?

Once the user logs in, they can navigate freely to any protected routes because their login status is stored in the Vuex store and checked by the router guard.

You can also enhance the login experience by redirecting users back to the page they originally tried to access after they log in. This can be done by passing the intended destination in the query parameters:

Article content

Then in your navigation guard, you can modify the redirect like this:

Article content

Summary:

In this step, we’ve successfully protected certain routes by using Vue Router’s navigation guards. This ensures that only logged-in users can access specific pages, and unauthenticated users are redirected to the login page.

Next up, we’ll cover Step 4, where we’ll implement token refresh logic to handle token expiration and keep users logged in without interruption.


Step 4: Implementing Token Refresh Logic

In this step, we’ll implement token refresh logic. This ensures that when a user’s authentication token expires, we can automatically refresh it without forcing the user to log in again.

When dealing with token-based authentication, the access token (which is used to authorize requests) usually has an expiration time. Once it expires, the user would typically be logged out unless we have a system in place to refresh the token automatically.

To handle this, we can use refresh tokens. A refresh token is a longer-lived token that allows the app to request a new access token without asking the user to log in again.

Why Do We Need Token Refresh?

Most access tokens have a short lifespan for security reasons. If someone were to steal a token, they could only use it for a limited time. However, to avoid interrupting the user’s session, we use the refresh token to get a new access token when the old one expires.

Here’s how we can implement token refresh logic in our Vue.js app using Axios interceptors.

Setting Up Axios Interceptors for Token Refresh

We will modify Axios, the HTTP client we’re using, to check for token expiration on each request. If the token has expired, Axios will automatically use the refresh token to request a new access token.

1. Create a file called api.js inside your services directory. This file will handle all API requests and include the logic for refreshing tokens.

Explanation:

Request Interceptor: Before each request is sent, we check if the user is logged in by retrieving their data from localStorage. If the user has an access token, we add it to the request’s Authorization header so that the server knows the user is authenticated.

Response Interceptor: When the server returns a 401 Unauthorized error (which happens when the access token has expired), we intercept the error. We then use the refresh token to get a new access token. Once a new token is received, we retry the original request with the new token.

Retry Mechanism: The originalRequest._retry flag prevents the app from getting stuck in an infinite loop of retries.

Adding the Token Refresh Logic to Vuex

To make this work, we need to add a refreshToken action in our Vuex store. This action will call the backend to get a new access token using the refresh token.

Here’s how you can implement it in the auth.module.js file:

Article content

Explanation:

refreshToken(): This action sends a request to refresh the token using the AuthService. If successful, the new access token is stored in Vuex and localStorage. If it fails (for example, if the refresh token has expired), the user is logged out.

mutations:

• refreshToken(): Updates the state with the new access token when it is successfully refreshed.

• logout(): Logs the user out and clears their data from both the state and localStorage.

Conclusion

With the token refresh logic in place, your app can now handle access token expiration without requiring the user to log in again. The Axios interceptors ensure that every request is authenticated, and if a token expires, a new one is automatically obtained in the background.

The next step is to ensure that the user remains logged in even after refreshing the page by checking their login status on app startup.


Step 5: Keeping Users Logged In After Page Refresh

Here we’ll ensure that users remain logged in even after they refresh the page or close and reopen the app. This is crucial for providing a seamless user experience.

One common issue with authentication systems is that when a user refreshes the page or reopens the app, they may lose their logged-in status. To solve this, we can check for the user’s login state when the app starts up.

Since we’re already storing user information (like tokens) in localStorage, we can use that data to restore the user’s session automatically. We just need to check the stored tokens when the app is loaded and ensure that they are still valid.

Ensuring Users Stay Logged In

To achieve this, we will dispatch the refreshToken action from Vuex when the app starts. This will check if the refresh token is valid and, if so, will obtain a new access token to keep the user logged in.

Here’s how to do it:

1. Modify the main.js File

In your main.js file, which bootstraps the Vue application, we will dispatch the refreshToken action to check the user’s login status as soon as the app is initialized.

Article content

Explanation:

store.dispatch(‘auth/refreshToken’): This action is dispatched as soon as the app loads. It checks if there is a valid refresh token stored in localStorage and, if so, attempts to refresh the access token.

finally(): Once the token check is complete (whether successful or not), the app is mounted by calling new Vue(). This ensures that the app doesn’t load until the authentication state is determined.


2. Modify the Vuex Store’s refreshToken Action

We’ll make sure that the refreshToken action in the Vuex store handles the token validation process during app startup. If the refresh token is invalid or missing, the user will be logged out.

Here’s the updated version of the auth.module.js file:

Article content

Explanation:

initialState: When the app starts, the state is initialized by checking for the user data stored in localStorage. If the user exists and has a token, they are considered logged in.

refreshToken action: This action checks if the user has a refresh token stored. If they do, it attempts to refresh the access token. If the refresh fails (for example, if the refresh token is expired), the user is logged out.

mutations: The refreshToken mutation updates the access token when it is refreshed, and the logout mutation clears the user data when the user logs out.

What Happens on Page Refresh?

When the page is refreshed, the app will recheck the user’s login status by looking at the data stored in localStorage. If a valid refresh token is available, a new access token is generated to keep the user logged in. If the refresh token is invalid, the user will be logged out and prompted to log in again.

Summary:

With this step, your app can now automatically restore the user’s session after a page refresh or reopening the app. By checking for a valid refresh token on startup, you ensure that users remain logged in as long as their tokens are valid.


Conclusion

Congratulations! You’ve now set up a complete authentication system in your Vue.js application that handles everything from logging in, route protection, token refreshing, and maintaining session persistence across page refreshes.

This setup not only makes the app more secure but also improves user experience by keeping them logged in without interruptions.


ANAS ABDUSSALAM

Front End Dev | Computer Scientist | Tech Enthusiastic | Vuejs

6mo

Very helpful👍

Like
Reply

To view or add a comment, sign in

More articles by Aman Yerpude

Insights from the community

Others also viewed

Explore topics