Post

BootCamp Tutorial 2: Vue.js Fundamentals: Setting Up Authentication & Routing

πŸ“Œ Learning Objectives

Now that you’ve learned the basics of Vue.js authentication with Login & Signup, in this tutorial, we will review: βœ… Vue Project Structure
βœ… Configuring Vue Router for Navigation
βœ… Handling Authentication (Login & Signup) Using API
βœ… Storing JWT Token Locally

By the end of this tutorial, you’ll have a working authentication system with routing in Vue.js.


1️⃣ Setting Up Vue Project Structure

A typical Vue.js project contains the following key files:

1
2
3
4
5
6
7
8
9
10
11
12
πŸ“‚ vue-auth-project/
 β”œβ”€β”€ πŸ“‚ src/
 β”‚   β”œβ”€β”€ πŸ“‚ components/         # Reusable components (optional)
 β”‚   β”œβ”€β”€ πŸ“‚ views/              # Main pages (Login, Signup, Home)
 β”‚   β”œβ”€β”€ πŸ“‚ router/             # Vue Router Configuration
 β”‚   β”‚   β”œβ”€β”€ index.js
 β”‚   β”œβ”€β”€ πŸ“‚ assets/             # Static assets (images, CSS)
 β”‚   β”œβ”€β”€ App.vue                # Root Vue component
 β”‚   β”œβ”€β”€ main.js                # Main entry file
 β”œβ”€β”€ index.html                 # Base HTML file
 β”œβ”€β”€ vite.config.js             # Vite configuration (for Vue)
 β”œβ”€β”€ package.json               # Dependencies & scripts

2️⃣ Configuring Vue.js with Routing

πŸ“Œ main.js - Registering Vue App & Router

πŸ“‚ src/main.js

1
2
3
4
5
6
7
import { createApp } from 'vue';
import App from './App.vue';
import router from './router';

const app = createApp(App);
app.use(router);
app.mount('#app');

βœ… This initializes the Vue application and registers the router.


πŸ“Œ App.vue - Root Component

πŸ“‚ src/App.vue

1
2
3
<template>
  <RouterView />
</template>

βœ… <RouterView /> is a placeholder for dynamically loaded pages.

  • It loads different pages based on the URL path.

πŸ“Œ index.html - The Main Entry Point

πŸ“‚ public/index.html

1
2
3
4
5
6
7
8
9
10
11
12
13
<!doctype html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <link rel="icon" type="image/svg+xml" href="/vite.svg" />
  <meta name="viewport" content="width=device-width, initial-scale=1.0" />
  <title>Vite + Vue</title>
</head>
<body>
  <div id="app"></div>
  <script type="module" src="/src/main.js"></script>
</body>
</html>

βœ… Vue renders the app inside <div id="app"></div>.


3️⃣ Setting Up Vue Router

πŸ“Œ router/index.js - Defining Routes

πŸ“‚ src/router/index.js

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
import { createRouter, createWebHistory } from 'vue-router';
import Home from '../views/HomeView.vue';
import Login from '../views/LoginView.vue';
import Signup from '../views/SignupView.vue';

const router = createRouter({
    history: createWebHistory(import.meta.env.BASE_URL),
    routes: [
        { path: '/', name: 'home', component: Home },
        { path: '/login', name: 'login', component: Login },
        { path: '/signup', name: 'signup', component: Signup }
    ]
});

export default router;

βœ… Key Features:

  • Uses createWebHistory() for clean URLs (/login instead of #/login).
  • Defines routes (/, /login, /signup).
  • Each route loads a view component dynamically.

4️⃣ Creating Authentication Pages

πŸ”₯ Login Page

πŸ“‚ src/views/LoginView.vue

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
<template>
  <h2>Login</h2>
  <form @submit.prevent="loginUser">
    <div>
      <label for="email">Email</label>
      <input type="email" id="email" v-model="email" required />
    </div>
    <div>
      <label for="password">Password</label>
      <input type="password" id="password" v-model="password" required />
    </div>
    <button type="submit">Login</button>
  </form>

  <div>
    <RouterLink to="/">Home</RouterLink> | 
    <RouterLink to="/signup">Signup</RouterLink>
  </div>
</template>

<script>
export default {
  data() {
    return {
      email: "",
      password: "",
    };
  },
  methods: {
    async loginUser() {
      if (!this.email || !this.password) {
        alert("All fields are required!");
        return;
      }

      try {
        const response = await fetch("http://localhost:5000/login", {
          method: "POST",
          headers: { "Content-Type": "application/json" },
          body: JSON.stringify({ email: this.email, password: this.password })
        });

        const res = await response.json();
        if (res.token) {
          localStorage.setItem("token", res.token);
          alert("Login successful!");
          this.$router.push("/"); // Redirect to Home
        } else {
          alert("Invalid login credentials.");
        }
      } catch (error) {
        alert("Login failed! Please try again.");
      }
    }
  }
};
</script>

βœ… Key Features:

  • Form submission using @submit.prevent
  • Stores JWT token in localStorage
  • Redirects user after login (this.$router.push("/"))

πŸ”₯ Signup Page

πŸ“‚ src/views/SignupView.vue

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
<template>
  <h2>Signup</h2>
  <form @submit.prevent="signupUser">
    <div>
      <label for="username">Username</label>
      <input type="text" id="username" v-model="username" required />
    </div>
    <div>
      <label for="email">Email</label>
      <input type="email" id="email" v-model="email" required />
    </div>
    <div>
      <label for="password">Password</label>
      <input type="password" id="password" v-model="password" required />
    </div>
    <button type="submit">Sign Up</button>
  </form>

  <div>
    <RouterLink to="/">Home</RouterLink> | 
    <RouterLink to="/login">Login</RouterLink>
  </div>
</template>

<script>
import axios from "axios";

export default {
  data() {
    return {
      username: "",
      email: "",
      password: "",
    };
  },
  methods: {
    async signupUser() {
      if (!this.username || !this.email || !this.password) {
        alert("All fields are required!");
        return;
      }

      try {
        const response = await axios.post("http://localhost:5000/signup", {
          username: this.username,
          email: this.email,
          password: this.password
        });

        alert(response.data.message || "Signup successful");
        this.$router.push("/login"); // Redirect to Login
      } catch (error) {
        alert(error.response?.data.message || "Signup failed!");
      }
    }
  }
};
</script>

βœ… Key Features:

  • Uses axios for API requests
  • Handles signup validation
  • Redirects user to login page on success

5️⃣ Adding Navigation

πŸ“‚ src/components/Navbar.vue

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
<template>
  <nav>
    <RouterLink to="/">Home</RouterLink> | 
    <RouterLink v-if="!isAuthenticated" to="/login">Login</RouterLink> | 
    <RouterLink v-if="!isAuthenticated" to="/signup">Signup</RouterLink> |
    <button v-if="isAuthenticated" @click="logout">Logout</button>
  </nav>
</template>

<script>
export default {
  computed: {
    isAuthenticated() {
      return !!localStorage.getItem("token");
    }
  },
  methods: {
    logout() {
      localStorage.removeItem("token");
      this.$router.push("/login");
    }
  }
};
</script>

βœ… This creates a dynamic navbar that:

  • Shows Login/Signup if the user is not logged in
  • Shows Logout if the user is logged in
  • Clears token & redirects on logout

πŸš€ Next:

Mastering Decorators & Database Communication in Flask API

Vue.js Advanced API Integration with Role-Based Access

This post is licensed under CC BY 4.0 by the author.