[
  {
    "path": ".gitignore",
    "content": ".DS_Store\nnode_modules\n/dist\n\n\n# local env files\n.env.local\n.env.*.local\n\n# Log files\nnpm-debug.log*\nyarn-debug.log*\nyarn-error.log*\npnpm-debug.log*\n\n# Editor directories and files\n.idea\n.vscode\n*.suo\n*.ntvs*\n*.njsproj\n*.sln\n*.sw?\n"
  },
  {
    "path": "README.md",
    "content": "# Vue 3 Authentication with JWT, Vuex and Vue Router\n\n## Flow for User Registration and User Login\n\n![vue-3-authentication-jwt-example-flow](vue-3-authentication-jwt-example-flow.png)\n\n- Signup Page:\n\n![vue-3-authentication-jwt-example-vuex-user-registration](vue-3-authentication-jwt-example-vuex-user-registration.png)\n\n- Form Validation could look like this:\n\n![vue-3-authentication-jwt-example-vuex-form-validation](vue-3-authentication-jwt-example-vuex-form-validation.png)\n\n- Login Page & Profile Page (for successful Login):\n\n![vue-3-authentication-jwt-example-vuex-user-login](vue-3-authentication-jwt-example-vuex-user-login.png)\n\nFor instruction, please visit:\n> [Vue 3 Authentication & Authorization with JWT, Vuex and Vue Router](https://bezkoder.com/vue-3-authentication-jwt/)\n\n## Note:\nOpen `src/services/auth-header.js` and modify `return` statement for appropriate back-end.\n\n```js\nexport default function authHeader() {\n  let user = JSON.parse(localStorage.getItem('user'));\n\n  if (user && user.accessToken) {\n    return { Authorization: 'Bearer ' + user.accessToken }; // for Spring Boot back-end\n    // return { 'x-access-token': user.accessToken };       // for Node.js Express back-end\n  } else {\n    return {};\n  }\n}\n```\n\nRelated Posts:\n> [Vue 2 JWT Authentication with Vuex and Vue Router](https://bezkoder.com/jwt-vue-vuex-authentication/)\n\n> [Using Typescript](https://bezkoder.com/vuex-typescript-jwt-auth/)\n\n> [Vue 3 CRUD example with Axios and Vue Router](https://bezkoder.com/vue-3-crud/)\n\nFullstack with Spring Boot Back-end:\n> [Spring Boot + Vue.js: Authentication with JWT & Spring Security Example](https://bezkoder.com/spring-boot-vue-js-authentication-jwt-spring-security/)\n\nFullstack with Node.js Express Back-end:\n> [Node.js Express + Vue.js: JWT Authentication & Authorization example](https://bezkoder.com/node-express-vue-jwt-auth/)\n\nFullstack CRUD:\n> [Vue.js + Node.js + Express + MySQL example](https://bezkoder.com/vue-js-node-js-express-mysql-crud-example/)\n\n> [Vue.js + Node.js + Express + PostgreSQL example](https://bezkoder.com/vue-node-express-postgresql/)\n\n> [Vue.js + Node.js + Express + MongoDB example](https://bezkoder.com/vue-node-express-mongodb-mevn-crud/)\n\n> [Vue.js + Spring Boot + MySQL/PostgreSQL example](https://bezkoder.com/spring-boot-vue-js-crud-example/)\n\n> [Vue.js + Spring Boot + MongoDB example](https://bezkoder.com/spring-boot-vue-mongodb/)\n\n> [Vue.js + Django example](https://bezkoder.com/django-vue-js-rest-framework/)\n\nIntegration (run on same server/port):\n> [Integrate Vue.js with Spring Boot](https://bezkoder.com/integrate-vue-spring-boot/)\n\n> [Integrate Vue App with Node.js Express](https://bezkoder.com/serve-vue-app-express/)\n\n\n## Project setup\n```\nnpm install\n```\n\n### Compiles and hot-reloads for development\n```\nnpm run serve\n```\n\n### Compiles and minifies for production\n```\nnpm run build\n```\n\n### Lints and fixes files\n```\nnpm run lint\n```\n\n### Customize configuration\nSee [Configuration Reference](https://cli.vuejs.org/config/).\n"
  },
  {
    "path": "babel.config.js",
    "content": "module.exports = {\n  presets: [\n    '@vue/cli-plugin-babel/preset'\n  ]\n}\n"
  },
  {
    "path": "package.json",
    "content": "{\n  \"name\": \"vue-3-authentication-jwt\",\n  \"version\": \"0.1.0\",\n  \"private\": true,\n  \"scripts\": {\n    \"serve\": \"vue-cli-service serve\",\n    \"build\": \"vue-cli-service build\",\n    \"lint\": \"vue-cli-service lint\"\n  },\n  \"dependencies\": {\n    \"@fortawesome/fontawesome-svg-core\": \"^1.2.35\",\n    \"@fortawesome/free-solid-svg-icons\": \"^5.15.3\",\n    \"@fortawesome/vue-fontawesome\": \"^3.0.0-3\",\n    \"axios\": \"^0.21.1\",\n    \"bootstrap\": \"^4.6.0\",\n    \"core-js\": \"^3.6.5\",\n    \"jquery\": \"^3.6.0\",\n    \"popper.js\": \"^1.16.1\",\n    \"vee-validate\": \"^4.3.5\",\n    \"vue\": \"^3.0.0\",\n    \"vue-router\": \"^4.0.6\",\n    \"vuex\": \"^4.0.0\",\n    \"yup\": \"^0.32.9\"\n  },\n  \"devDependencies\": {\n    \"@vue/cli-plugin-babel\": \"~4.5.0\",\n    \"@vue/cli-plugin-eslint\": \"~4.5.0\",\n    \"@vue/cli-service\": \"~4.5.0\",\n    \"@vue/compiler-sfc\": \"^3.0.0\",\n    \"babel-eslint\": \"^10.1.0\",\n    \"eslint\": \"^6.7.2\",\n    \"eslint-plugin-vue\": \"^7.0.0\"\n  },\n  \"eslintConfig\": {\n    \"root\": true,\n    \"env\": {\n      \"node\": true\n    },\n    \"extends\": [\n      \"plugin:vue/vue3-essential\",\n      \"eslint:recommended\"\n    ],\n    \"parserOptions\": {\n      \"parser\": \"babel-eslint\"\n    },\n    \"rules\": {}\n  },\n  \"browserslist\": [\n    \"> 1%\",\n    \"last 2 versions\",\n    \"not dead\"\n  ]\n}\n"
  },
  {
    "path": "public/index.html",
    "content": "<!DOCTYPE html>\n<html lang=\"\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <meta name=\"viewport\" content=\"width=device-width,initial-scale=1.0\">\n    <link rel=\"icon\" href=\"<%= BASE_URL %>favicon.ico\">\n    <title><%= htmlWebpackPlugin.options.title %></title>\n  </head>\n  <body>\n    <noscript>\n      <strong>We're sorry but <%= htmlWebpackPlugin.options.title %> doesn't work properly without JavaScript enabled. Please enable it to continue.</strong>\n    </noscript>\n    <div id=\"app\"></div>\n    <!-- built files will be auto injected -->\n  </body>\n</html>\n"
  },
  {
    "path": "src/App.vue",
    "content": "<template>\n  <div id=\"app\">\n    <nav class=\"navbar navbar-expand navbar-dark bg-dark\">\n      <a href=\"/\" class=\"navbar-brand\">bezKoder</a>\n      <div class=\"navbar-nav mr-auto\">\n        <li class=\"nav-item\">\n          <router-link to=\"/home\" class=\"nav-link\">\n            <font-awesome-icon icon=\"home\" /> Home\n          </router-link>\n        </li>\n        <li v-if=\"showAdminBoard\" class=\"nav-item\">\n          <router-link to=\"/admin\" class=\"nav-link\">Admin Board</router-link>\n        </li>\n        <li v-if=\"showModeratorBoard\" class=\"nav-item\">\n          <router-link to=\"/mod\" class=\"nav-link\">Moderator Board</router-link>\n        </li>\n        <li class=\"nav-item\">\n          <router-link v-if=\"currentUser\" to=\"/user\" class=\"nav-link\">User</router-link>\n        </li>\n      </div>\n\n      <div v-if=\"!currentUser\" class=\"navbar-nav ml-auto\">\n        <li class=\"nav-item\">\n          <router-link to=\"/register\" class=\"nav-link\">\n            <font-awesome-icon icon=\"user-plus\" /> Sign Up\n          </router-link>\n        </li>\n        <li class=\"nav-item\">\n          <router-link to=\"/login\" class=\"nav-link\">\n            <font-awesome-icon icon=\"sign-in-alt\" /> Login\n          </router-link>\n        </li>\n      </div>\n\n      <div v-if=\"currentUser\" class=\"navbar-nav ml-auto\">\n        <li class=\"nav-item\">\n          <router-link to=\"/profile\" class=\"nav-link\">\n            <font-awesome-icon icon=\"user\" />\n            {{ currentUser.username }}\n          </router-link>\n        </li>\n        <li class=\"nav-item\">\n          <a class=\"nav-link\" @click.prevent=\"logOut\">\n            <font-awesome-icon icon=\"sign-out-alt\" /> LogOut\n          </a>\n        </li>\n      </div>\n    </nav>\n\n    <div class=\"container\">\n      <router-view />\n    </div>\n  </div>\n</template>\n\n<script>\nexport default {\n  computed: {\n    currentUser() {\n      return this.$store.state.auth.user;\n    },\n    showAdminBoard() {\n      if (this.currentUser && this.currentUser['roles']) {\n        return this.currentUser['roles'].includes('ROLE_ADMIN');\n      }\n\n      return false;\n    },\n    showModeratorBoard() {\n      if (this.currentUser && this.currentUser['roles']) {\n        return this.currentUser['roles'].includes('ROLE_MODERATOR');\n      }\n\n      return false;\n    }\n  },\n  methods: {\n    logOut() {\n      this.$store.dispatch('auth/logout');\n      this.$router.push('/login');\n    }\n  }\n};\n</script>\n"
  },
  {
    "path": "src/components/BoardAdmin.vue",
    "content": "<template>\n  <div class=\"container\">\n    <header class=\"jumbotron\">\n      <h3>{{ content }}</h3>\n    </header>\n  </div>\n</template>\n\n<script>\nimport UserService from \"../services/user.service\";\n\nexport default {\n  name: \"Admin\",\n  data() {\n    return {\n      content: \"\",\n    };\n  },\n  mounted() {\n    UserService.getAdminBoard().then(\n      (response) => {\n        this.content = response.data;\n      },\n      (error) => {\n        this.content =\n          (error.response &&\n            error.response.data &&\n            error.response.data.message) ||\n          error.message ||\n          error.toString();\n      }\n    );\n  },\n};\n</script>\n"
  },
  {
    "path": "src/components/BoardModerator.vue",
    "content": "<template>\n  <div class=\"container\">\n    <header class=\"jumbotron\">\n      <h3>{{ content }}</h3>\n    </header>\n  </div>\n</template>\n\n<script>\nimport UserService from \"../services/user.service\";\n\nexport default {\n  name: \"Moderator\",\n  data() {\n    return {\n      content: \"\",\n    };\n  },\n  mounted() {\n    UserService.getModeratorBoard().then(\n      (response) => {\n        this.content = response.data;\n      },\n      (error) => {\n        this.content =\n          (error.response &&\n            error.response.data &&\n            error.response.data.message) ||\n          error.message ||\n          error.toString();\n      }\n    );\n  },\n};\n</script>\n"
  },
  {
    "path": "src/components/BoardUser.vue",
    "content": "<template>\n  <div class=\"container\">\n    <header class=\"jumbotron\">\n      <h3>{{ content }}</h3>\n    </header>\n  </div>\n</template>\n\n<script>\nimport UserService from \"../services/user.service\";\n\nexport default {\n  name: \"User\",\n  data() {\n    return {\n      content: \"\",\n    };\n  },\n  mounted() {\n    UserService.getUserBoard().then(\n      (response) => {\n        this.content = response.data;\n      },\n      (error) => {\n        this.content =\n          (error.response &&\n            error.response.data &&\n            error.response.data.message) ||\n          error.message ||\n          error.toString();\n      }\n    );\n  },\n};\n</script>\n"
  },
  {
    "path": "src/components/Home.vue",
    "content": "<template>\n  <div class=\"container\">\n    <header class=\"jumbotron\">\n      <h3>{{ content }}</h3>\n    </header>\n  </div>\n</template>\n\n<script>\nimport UserService from \"../services/user.service\";\n\nexport default {\n  name: \"Home\",\n  data() {\n    return {\n      content: \"\",\n    };\n  },\n  mounted() {\n    UserService.getPublicContent().then(\n      (response) => {\n        this.content = response.data;\n      },\n      (error) => {\n        this.content =\n          (error.response &&\n            error.response.data &&\n            error.response.data.message) ||\n          error.message ||\n          error.toString();\n      }\n    );\n  },\n};\n</script>\n"
  },
  {
    "path": "src/components/Login.vue",
    "content": "<template>\n  <div class=\"col-md-12\">\n    <div class=\"card card-container\">\n      <img\n        id=\"profile-img\"\n        src=\"//ssl.gstatic.com/accounts/ui/avatar_2x.png\"\n        class=\"profile-img-card\"\n      />\n      <Form @submit=\"handleLogin\" :validation-schema=\"schema\">\n        <div class=\"form-group\">\n          <label for=\"username\">Username</label>\n          <Field name=\"username\" type=\"text\" class=\"form-control\" />\n          <ErrorMessage name=\"username\" class=\"error-feedback\" />\n        </div>\n        <div class=\"form-group\">\n          <label for=\"password\">Password</label>\n          <Field name=\"password\" type=\"password\" class=\"form-control\" />\n          <ErrorMessage name=\"password\" class=\"error-feedback\" />\n        </div>\n\n        <div class=\"form-group\">\n          <button class=\"btn btn-primary btn-block\" :disabled=\"loading\">\n            <span\n              v-show=\"loading\"\n              class=\"spinner-border spinner-border-sm\"\n            ></span>\n            <span>Login</span>\n          </button>\n        </div>\n\n        <div class=\"form-group\">\n          <div v-if=\"message\" class=\"alert alert-danger\" role=\"alert\">\n            {{ message }}\n          </div>\n        </div>\n      </Form>\n    </div>\n  </div>\n</template>\n\n<script>\nimport { Form, Field, ErrorMessage } from \"vee-validate\";\nimport * as yup from \"yup\";\n\nexport default {\n  name: \"Login\",\n  components: {\n    Form,\n    Field,\n    ErrorMessage,\n  },\n  data() {\n    const schema = yup.object().shape({\n      username: yup.string().required(\"Username is required!\"),\n      password: yup.string().required(\"Password is required!\"),\n    });\n\n    return {\n      loading: false,\n      message: \"\",\n      schema,\n    };\n  },\n  computed: {\n    loggedIn() {\n      return this.$store.state.auth.status.loggedIn;\n    },\n  },\n  created() {\n    if (this.loggedIn) {\n      this.$router.push(\"/profile\");\n    }\n  },\n  methods: {\n    handleLogin(user) {\n      this.loading = true;\n\n      this.$store.dispatch(\"auth/login\", user).then(\n        () => {\n          this.$router.push(\"/profile\");\n        },\n        (error) => {\n          this.loading = false;\n          this.message =\n            (error.response &&\n              error.response.data &&\n              error.response.data.message) ||\n            error.message ||\n            error.toString();\n        }\n      );\n    },\n  },\n};\n</script>\n\n<style scoped>\nlabel {\n  display: block;\n  margin-top: 10px;\n}\n\n.card-container.card {\n  max-width: 350px !important;\n  padding: 40px 40px;\n}\n\n.card {\n  background-color: #f7f7f7;\n  padding: 20px 25px 30px;\n  margin: 0 auto 25px;\n  margin-top: 50px;\n  -moz-border-radius: 2px;\n  -webkit-border-radius: 2px;\n  border-radius: 2px;\n  -moz-box-shadow: 0px 2px 2px rgba(0, 0, 0, 0.3);\n  -webkit-box-shadow: 0px 2px 2px rgba(0, 0, 0, 0.3);\n  box-shadow: 0px 2px 2px rgba(0, 0, 0, 0.3);\n}\n\n.profile-img-card {\n  width: 96px;\n  height: 96px;\n  margin: 0 auto 10px;\n  display: block;\n  -moz-border-radius: 50%;\n  -webkit-border-radius: 50%;\n  border-radius: 50%;\n}\n\n.error-feedback {\n  color: red;\n}\n</style>\n"
  },
  {
    "path": "src/components/Profile.vue",
    "content": "<template>\n  <div class=\"container\">\n    <header class=\"jumbotron\">\n      <h3>\n        <strong>{{currentUser.username}}</strong> Profile\n      </h3>\n    </header>\n    <p>\n      <strong>Token:</strong>\n      {{currentUser.accessToken.substring(0, 20)}} ... {{currentUser.accessToken.substr(currentUser.accessToken.length - 20)}}\n    </p>\n    <p>\n      <strong>Id:</strong>\n      {{currentUser.id}}\n    </p>\n    <p>\n      <strong>Email:</strong>\n      {{currentUser.email}}\n    </p>\n    <strong>Authorities:</strong>\n    <ul>\n      <li v-for=\"role in currentUser.roles\" :key=\"role\">{{role}}</li>\n    </ul>\n  </div>\n</template>\n\n<script>\nexport default {\n  name: 'Profile',\n  computed: {\n    currentUser() {\n      return this.$store.state.auth.user;\n    }\n  },\n  mounted() {\n    if (!this.currentUser) {\n      this.$router.push('/login');\n    }\n  }\n};\n</script>"
  },
  {
    "path": "src/components/Register.vue",
    "content": "<template>\n  <div class=\"col-md-12\">\n    <div class=\"card card-container\">\n      <img\n        id=\"profile-img\"\n        src=\"//ssl.gstatic.com/accounts/ui/avatar_2x.png\"\n        class=\"profile-img-card\"\n      />\n      <Form @submit=\"handleRegister\" :validation-schema=\"schema\">\n        <div v-if=\"!successful\">\n          <div class=\"form-group\">\n            <label for=\"username\">Username</label>\n            <Field name=\"username\" type=\"text\" class=\"form-control\" />\n            <ErrorMessage name=\"username\" class=\"error-feedback\" />\n          </div>\n          <div class=\"form-group\">\n            <label for=\"email\">Email</label>\n            <Field name=\"email\" type=\"email\" class=\"form-control\" />\n            <ErrorMessage name=\"email\" class=\"error-feedback\" />\n          </div>\n          <div class=\"form-group\">\n            <label for=\"password\">Password</label>\n            <Field name=\"password\" type=\"password\" class=\"form-control\" />\n            <ErrorMessage name=\"password\" class=\"error-feedback\" />\n          </div>\n\n          <div class=\"form-group\">\n            <button class=\"btn btn-primary btn-block\" :disabled=\"loading\">\n              <span\n                v-show=\"loading\"\n                class=\"spinner-border spinner-border-sm\"\n              ></span>\n              Sign Up\n            </button>\n          </div>\n        </div>\n      </Form>\n\n      <div\n        v-if=\"message\"\n        class=\"alert\"\n        :class=\"successful ? 'alert-success' : 'alert-danger'\"\n      >\n        {{ message }}\n      </div>\n    </div>\n  </div>\n</template>\n\n<script>\nimport { Form, Field, ErrorMessage } from \"vee-validate\";\nimport * as yup from \"yup\";\n\nexport default {\n  name: \"Register\",\n  components: {\n    Form,\n    Field,\n    ErrorMessage,\n  },\n  data() {\n    const schema = yup.object().shape({\n      username: yup\n        .string()\n        .required(\"Username is required!\")\n        .min(3, \"Must be at least 3 characters!\")\n        .max(20, \"Must be maximum 20 characters!\"),\n      email: yup\n        .string()\n        .required(\"Email is required!\")\n        .email(\"Email is invalid!\")\n        .max(50, \"Must be maximum 50 characters!\"),\n      password: yup\n        .string()\n        .required(\"Password is required!\")\n        .min(6, \"Must be at least 6 characters!\")\n        .max(40, \"Must be maximum 40 characters!\"),\n    });\n\n    return {\n      successful: false,\n      loading: false,\n      message: \"\",\n      schema,\n    };\n  },\n  computed: {\n    loggedIn() {\n      return this.$store.state.auth.status.loggedIn;\n    },\n  },\n  mounted() {\n    if (this.loggedIn) {\n      this.$router.push(\"/profile\");\n    }\n  },\n  methods: {\n    handleRegister(user) {\n      this.message = \"\";\n      this.successful = false;\n      this.loading = true;\n\n      this.$store.dispatch(\"auth/register\", user).then(\n        (data) => {\n          this.message = data.message;\n          this.successful = true;\n          this.loading = false;\n        },\n        (error) => {\n          this.message =\n            (error.response &&\n              error.response.data &&\n              error.response.data.message) ||\n            error.message ||\n            error.toString();\n          this.successful = false;\n          this.loading = false;\n        }\n      );\n    },\n  },\n};\n</script>\n\n<style scoped>\nlabel {\n  display: block;\n  margin-top: 10px;\n}\n\n.card-container.card {\n  max-width: 350px !important;\n  padding: 40px 40px;\n}\n\n.card {\n  background-color: #f7f7f7;\n  padding: 20px 25px 30px;\n  margin: 0 auto 25px;\n  margin-top: 50px;\n  -moz-border-radius: 2px;\n  -webkit-border-radius: 2px;\n  border-radius: 2px;\n  -moz-box-shadow: 0px 2px 2px rgba(0, 0, 0, 0.3);\n  -webkit-box-shadow: 0px 2px 2px rgba(0, 0, 0, 0.3);\n  box-shadow: 0px 2px 2px rgba(0, 0, 0, 0.3);\n}\n\n.profile-img-card {\n  width: 96px;\n  height: 96px;\n  margin: 0 auto 10px;\n  display: block;\n  -moz-border-radius: 50%;\n  -webkit-border-radius: 50%;\n  border-radius: 50%;\n}\n\n.error-feedback {\n  color: red;\n}\n</style>\n"
  },
  {
    "path": "src/main.js",
    "content": "import { createApp } from \"vue\";\nimport App from \"./App.vue\";\nimport router from \"./router\";\nimport store from \"./store\";\nimport \"bootstrap\";\nimport \"bootstrap/dist/css/bootstrap.min.css\";\nimport { FontAwesomeIcon } from './plugins/font-awesome'\n\ncreateApp(App)\n  .use(router)\n  .use(store)\n  .component(\"font-awesome-icon\", FontAwesomeIcon)\n  .mount(\"#app\");\n"
  },
  {
    "path": "src/plugins/font-awesome.js",
    "content": "import { library } from \"@fortawesome/fontawesome-svg-core\";\nimport { FontAwesomeIcon } from \"@fortawesome/vue-fontawesome\";\nimport {\n  faHome,\n  faUser,\n  faUserPlus,\n  faSignInAlt,\n  faSignOutAlt,\n} from \"@fortawesome/free-solid-svg-icons\";\n\nlibrary.add(faHome, faUser, faUserPlus, faSignInAlt, faSignOutAlt);\n\nexport { FontAwesomeIcon };\n"
  },
  {
    "path": "src/router.js",
    "content": "import { createWebHistory, createRouter } from \"vue-router\";\nimport Home from \"./components/Home.vue\";\nimport Login from \"./components/Login.vue\";\nimport Register from \"./components/Register.vue\";\n// lazy-loaded\nconst Profile = () => import(\"./components/Profile.vue\")\nconst BoardAdmin = () => import(\"./components/BoardAdmin.vue\")\nconst BoardModerator = () => import(\"./components/BoardModerator.vue\")\nconst BoardUser = () => import(\"./components/BoardUser.vue\")\n\nconst routes = [\n  {\n    path: \"/\",\n    name: \"home\",\n    component: Home,\n  },\n  {\n    path: \"/home\",\n    component: Home,\n  },\n  {\n    path: \"/login\",\n    component: Login,\n  },\n  {\n    path: \"/register\",\n    component: Register,\n  },\n  {\n    path: \"/profile\",\n    name: \"profile\",\n    // lazy-loaded\n    component: Profile,\n  },\n  {\n    path: \"/admin\",\n    name: \"admin\",\n    // lazy-loaded\n    component: BoardAdmin,\n  },\n  {\n    path: \"/mod\",\n    name: \"moderator\",\n    // lazy-loaded\n    component: BoardModerator,\n  },\n  {\n    path: \"/user\",\n    name: \"user\",\n    // lazy-loaded\n    component: BoardUser,\n  },\n];\n\nconst router = createRouter({\n  history: createWebHistory(),\n  routes,\n});\n\n// router.beforeEach((to, from, next) => {\n//   const publicPages = ['/login', '/register', '/home'];\n//   const authRequired = !publicPages.includes(to.path);\n//   const loggedIn = localStorage.getItem('user');\n\n//   // trying to access a restricted page + not logged in\n//   // redirect to login page\n//   if (authRequired && !loggedIn) {\n//     next('/login');\n//   } else {\n//     next();\n//   }\n// });\n\nexport default router;"
  },
  {
    "path": "src/services/auth-header.js",
    "content": "export default function authHeader() {\n  let user = JSON.parse(localStorage.getItem('user'));\n\n  if (user && user.accessToken) {\n    return { Authorization: 'Bearer ' + user.accessToken }; // for Spring Boot back-end\n    // return { 'x-access-token': user.accessToken };       // for Node.js Express back-end\n  } else {\n    return {};\n  }\n}\n"
  },
  {
    "path": "src/services/auth.service.js",
    "content": "import axios from 'axios';\n\nconst API_URL = 'http://localhost:8080/api/auth/';\n\nclass AuthService {\n  login(user) {\n    return axios\n      .post(API_URL + 'signin', {\n        username: user.username,\n        password: user.password\n      })\n      .then(response => {\n        if (response.data.accessToken) {\n          localStorage.setItem('user', JSON.stringify(response.data));\n        }\n\n        return response.data;\n      });\n  }\n\n  logout() {\n    localStorage.removeItem('user');\n  }\n\n  register(user) {\n    return axios.post(API_URL + 'signup', {\n      username: user.username,\n      email: user.email,\n      password: user.password\n    });\n  }\n}\n\nexport default new AuthService();\n"
  },
  {
    "path": "src/services/user.service.js",
    "content": "import axios from 'axios';\nimport authHeader from './auth-header';\n\nconst API_URL = 'http://localhost:8080/api/test/';\n\nclass UserService {\n  getPublicContent() {\n    return axios.get(API_URL + 'all');\n  }\n\n  getUserBoard() {\n    return axios.get(API_URL + 'user', { headers: authHeader() });\n  }\n\n  getModeratorBoard() {\n    return axios.get(API_URL + 'mod', { headers: authHeader() });\n  }\n\n  getAdminBoard() {\n    return axios.get(API_URL + 'admin', { headers: authHeader() });\n  }\n}\n\nexport default new UserService();\n"
  },
  {
    "path": "src/store/auth.module.js",
    "content": "import AuthService from '../services/auth.service';\n\nconst user = JSON.parse(localStorage.getItem('user'));\nconst initialState = user\n  ? { status: { loggedIn: true }, user }\n  : { status: { loggedIn: false }, user: null };\n\nexport const auth = {\n  namespaced: true,\n  state: initialState,\n  actions: {\n    login({ commit }, user) {\n      return AuthService.login(user).then(\n        user => {\n          commit('loginSuccess', user);\n          return Promise.resolve(user);\n        },\n        error => {\n          commit('loginFailure');\n          return Promise.reject(error);\n        }\n      );\n    },\n    logout({ commit }) {\n      AuthService.logout();\n      commit('logout');\n    },\n    register({ commit }, user) {\n      return AuthService.register(user).then(\n        response => {\n          commit('registerSuccess');\n          return Promise.resolve(response.data);\n        },\n        error => {\n          commit('registerFailure');\n          return Promise.reject(error);\n        }\n      );\n    }\n  },\n  mutations: {\n    loginSuccess(state, user) {\n      state.status.loggedIn = true;\n      state.user = user;\n    },\n    loginFailure(state) {\n      state.status.loggedIn = false;\n      state.user = null;\n    },\n    logout(state) {\n      state.status.loggedIn = false;\n      state.user = null;\n    },\n    registerSuccess(state) {\n      state.status.loggedIn = false;\n    },\n    registerFailure(state) {\n      state.status.loggedIn = false;\n    }\n  }\n};\n"
  },
  {
    "path": "src/store/index.js",
    "content": "import { createStore } from \"vuex\";\nimport { auth } from \"./auth.module\";\n\nconst store = createStore({\n  modules: {\n    auth,\n  },\n});\n\nexport default store;\n"
  },
  {
    "path": "vue.config.js",
    "content": "module.exports = {\n  devServer: {\n    port: 8081\n  }\n}"
  }
]