Repository: bezkoder/vue-3-authentication-jwt
Branch: master
Commit: ca3b629b0559
Files: 22
Total size: 23.0 KB
Directory structure:
gitextract__tosskch/
├── .gitignore
├── README.md
├── babel.config.js
├── package.json
├── public/
│ └── index.html
├── src/
│ ├── App.vue
│ ├── components/
│ │ ├── BoardAdmin.vue
│ │ ├── BoardModerator.vue
│ │ ├── BoardUser.vue
│ │ ├── Home.vue
│ │ ├── Login.vue
│ │ ├── Profile.vue
│ │ └── Register.vue
│ ├── main.js
│ ├── plugins/
│ │ └── font-awesome.js
│ ├── router.js
│ ├── services/
│ │ ├── auth-header.js
│ │ ├── auth.service.js
│ │ └── user.service.js
│ └── store/
│ ├── auth.module.js
│ └── index.js
└── vue.config.js
================================================
FILE CONTENTS
================================================
================================================
FILE: .gitignore
================================================
.DS_Store
node_modules
/dist
# local env files
.env.local
.env.*.local
# Log files
npm-debug.log*
yarn-debug.log*
yarn-error.log*
pnpm-debug.log*
# Editor directories and files
.idea
.vscode
*.suo
*.ntvs*
*.njsproj
*.sln
*.sw?
================================================
FILE: README.md
================================================
# Vue 3 Authentication with JWT, Vuex and Vue Router
## Flow for User Registration and User Login

- Signup Page:

- Form Validation could look like this:

- Login Page & Profile Page (for successful Login):

For instruction, please visit:
> [Vue 3 Authentication & Authorization with JWT, Vuex and Vue Router](https://bezkoder.com/vue-3-authentication-jwt/)
## Note:
Open `src/services/auth-header.js` and modify `return` statement for appropriate back-end.
```js
export default function authHeader() {
let user = JSON.parse(localStorage.getItem('user'));
if (user && user.accessToken) {
return { Authorization: 'Bearer ' + user.accessToken }; // for Spring Boot back-end
// return { 'x-access-token': user.accessToken }; // for Node.js Express back-end
} else {
return {};
}
}
```
Related Posts:
> [Vue 2 JWT Authentication with Vuex and Vue Router](https://bezkoder.com/jwt-vue-vuex-authentication/)
> [Using Typescript](https://bezkoder.com/vuex-typescript-jwt-auth/)
> [Vue 3 CRUD example with Axios and Vue Router](https://bezkoder.com/vue-3-crud/)
Fullstack with Spring Boot Back-end:
> [Spring Boot + Vue.js: Authentication with JWT & Spring Security Example](https://bezkoder.com/spring-boot-vue-js-authentication-jwt-spring-security/)
Fullstack with Node.js Express Back-end:
> [Node.js Express + Vue.js: JWT Authentication & Authorization example](https://bezkoder.com/node-express-vue-jwt-auth/)
Fullstack CRUD:
> [Vue.js + Node.js + Express + MySQL example](https://bezkoder.com/vue-js-node-js-express-mysql-crud-example/)
> [Vue.js + Node.js + Express + PostgreSQL example](https://bezkoder.com/vue-node-express-postgresql/)
> [Vue.js + Node.js + Express + MongoDB example](https://bezkoder.com/vue-node-express-mongodb-mevn-crud/)
> [Vue.js + Spring Boot + MySQL/PostgreSQL example](https://bezkoder.com/spring-boot-vue-js-crud-example/)
> [Vue.js + Spring Boot + MongoDB example](https://bezkoder.com/spring-boot-vue-mongodb/)
> [Vue.js + Django example](https://bezkoder.com/django-vue-js-rest-framework/)
Integration (run on same server/port):
> [Integrate Vue.js with Spring Boot](https://bezkoder.com/integrate-vue-spring-boot/)
> [Integrate Vue App with Node.js Express](https://bezkoder.com/serve-vue-app-express/)
## Project setup
```
npm install
```
### Compiles and hot-reloads for development
```
npm run serve
```
### Compiles and minifies for production
```
npm run build
```
### Lints and fixes files
```
npm run lint
```
### Customize configuration
See [Configuration Reference](https://cli.vuejs.org/config/).
================================================
FILE: babel.config.js
================================================
module.exports = {
presets: [
'@vue/cli-plugin-babel/preset'
]
}
================================================
FILE: package.json
================================================
{
"name": "vue-3-authentication-jwt",
"version": "0.1.0",
"private": true,
"scripts": {
"serve": "vue-cli-service serve",
"build": "vue-cli-service build",
"lint": "vue-cli-service lint"
},
"dependencies": {
"@fortawesome/fontawesome-svg-core": "^1.2.35",
"@fortawesome/free-solid-svg-icons": "^5.15.3",
"@fortawesome/vue-fontawesome": "^3.0.0-3",
"axios": "^0.21.1",
"bootstrap": "^4.6.0",
"core-js": "^3.6.5",
"jquery": "^3.6.0",
"popper.js": "^1.16.1",
"vee-validate": "^4.3.5",
"vue": "^3.0.0",
"vue-router": "^4.0.6",
"vuex": "^4.0.0",
"yup": "^0.32.9"
},
"devDependencies": {
"@vue/cli-plugin-babel": "~4.5.0",
"@vue/cli-plugin-eslint": "~4.5.0",
"@vue/cli-service": "~4.5.0",
"@vue/compiler-sfc": "^3.0.0",
"babel-eslint": "^10.1.0",
"eslint": "^6.7.2",
"eslint-plugin-vue": "^7.0.0"
},
"eslintConfig": {
"root": true,
"env": {
"node": true
},
"extends": [
"plugin:vue/vue3-essential",
"eslint:recommended"
],
"parserOptions": {
"parser": "babel-eslint"
},
"rules": {}
},
"browserslist": [
"> 1%",
"last 2 versions",
"not dead"
]
}
================================================
FILE: public/index.html
================================================
<!DOCTYPE html>
<html lang="">
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width,initial-scale=1.0">
<link rel="icon" href="<%= BASE_URL %>favicon.ico">
<title><%= htmlWebpackPlugin.options.title %></title>
</head>
<body>
<noscript>
<strong>We're sorry but <%= htmlWebpackPlugin.options.title %> doesn't work properly without JavaScript enabled. Please enable it to continue.</strong>
</noscript>
<div id="app"></div>
<!-- built files will be auto injected -->
</body>
</html>
================================================
FILE: src/App.vue
================================================
<template>
<div id="app">
<nav class="navbar navbar-expand navbar-dark bg-dark">
<a href="/" class="navbar-brand">bezKoder</a>
<div class="navbar-nav mr-auto">
<li class="nav-item">
<router-link to="/home" class="nav-link">
<font-awesome-icon icon="home" /> Home
</router-link>
</li>
<li v-if="showAdminBoard" class="nav-item">
<router-link to="/admin" class="nav-link">Admin Board</router-link>
</li>
<li v-if="showModeratorBoard" class="nav-item">
<router-link to="/mod" class="nav-link">Moderator Board</router-link>
</li>
<li class="nav-item">
<router-link v-if="currentUser" to="/user" class="nav-link">User</router-link>
</li>
</div>
<div v-if="!currentUser" class="navbar-nav ml-auto">
<li class="nav-item">
<router-link to="/register" class="nav-link">
<font-awesome-icon icon="user-plus" /> Sign Up
</router-link>
</li>
<li class="nav-item">
<router-link to="/login" class="nav-link">
<font-awesome-icon icon="sign-in-alt" /> Login
</router-link>
</li>
</div>
<div v-if="currentUser" class="navbar-nav ml-auto">
<li class="nav-item">
<router-link to="/profile" class="nav-link">
<font-awesome-icon icon="user" />
{{ currentUser.username }}
</router-link>
</li>
<li class="nav-item">
<a class="nav-link" @click.prevent="logOut">
<font-awesome-icon icon="sign-out-alt" /> LogOut
</a>
</li>
</div>
</nav>
<div class="container">
<router-view />
</div>
</div>
</template>
<script>
export default {
computed: {
currentUser() {
return this.$store.state.auth.user;
},
showAdminBoard() {
if (this.currentUser && this.currentUser['roles']) {
return this.currentUser['roles'].includes('ROLE_ADMIN');
}
return false;
},
showModeratorBoard() {
if (this.currentUser && this.currentUser['roles']) {
return this.currentUser['roles'].includes('ROLE_MODERATOR');
}
return false;
}
},
methods: {
logOut() {
this.$store.dispatch('auth/logout');
this.$router.push('/login');
}
}
};
</script>
================================================
FILE: src/components/BoardAdmin.vue
================================================
<template>
<div class="container">
<header class="jumbotron">
<h3>{{ content }}</h3>
</header>
</div>
</template>
<script>
import UserService from "../services/user.service";
export default {
name: "Admin",
data() {
return {
content: "",
};
},
mounted() {
UserService.getAdminBoard().then(
(response) => {
this.content = response.data;
},
(error) => {
this.content =
(error.response &&
error.response.data &&
error.response.data.message) ||
error.message ||
error.toString();
}
);
},
};
</script>
================================================
FILE: src/components/BoardModerator.vue
================================================
<template>
<div class="container">
<header class="jumbotron">
<h3>{{ content }}</h3>
</header>
</div>
</template>
<script>
import UserService from "../services/user.service";
export default {
name: "Moderator",
data() {
return {
content: "",
};
},
mounted() {
UserService.getModeratorBoard().then(
(response) => {
this.content = response.data;
},
(error) => {
this.content =
(error.response &&
error.response.data &&
error.response.data.message) ||
error.message ||
error.toString();
}
);
},
};
</script>
================================================
FILE: src/components/BoardUser.vue
================================================
<template>
<div class="container">
<header class="jumbotron">
<h3>{{ content }}</h3>
</header>
</div>
</template>
<script>
import UserService from "../services/user.service";
export default {
name: "User",
data() {
return {
content: "",
};
},
mounted() {
UserService.getUserBoard().then(
(response) => {
this.content = response.data;
},
(error) => {
this.content =
(error.response &&
error.response.data &&
error.response.data.message) ||
error.message ||
error.toString();
}
);
},
};
</script>
================================================
FILE: src/components/Home.vue
================================================
<template>
<div class="container">
<header class="jumbotron">
<h3>{{ content }}</h3>
</header>
</div>
</template>
<script>
import UserService from "../services/user.service";
export default {
name: "Home",
data() {
return {
content: "",
};
},
mounted() {
UserService.getPublicContent().then(
(response) => {
this.content = response.data;
},
(error) => {
this.content =
(error.response &&
error.response.data &&
error.response.data.message) ||
error.message ||
error.toString();
}
);
},
};
</script>
================================================
FILE: src/components/Login.vue
================================================
<template>
<div class="col-md-12">
<div class="card card-container">
<img
id="profile-img"
src="//ssl.gstatic.com/accounts/ui/avatar_2x.png"
class="profile-img-card"
/>
<Form @submit="handleLogin" :validation-schema="schema">
<div class="form-group">
<label for="username">Username</label>
<Field name="username" type="text" class="form-control" />
<ErrorMessage name="username" class="error-feedback" />
</div>
<div class="form-group">
<label for="password">Password</label>
<Field name="password" type="password" class="form-control" />
<ErrorMessage name="password" class="error-feedback" />
</div>
<div class="form-group">
<button class="btn btn-primary btn-block" :disabled="loading">
<span
v-show="loading"
class="spinner-border spinner-border-sm"
></span>
<span>Login</span>
</button>
</div>
<div class="form-group">
<div v-if="message" class="alert alert-danger" role="alert">
{{ message }}
</div>
</div>
</Form>
</div>
</div>
</template>
<script>
import { Form, Field, ErrorMessage } from "vee-validate";
import * as yup from "yup";
export default {
name: "Login",
components: {
Form,
Field,
ErrorMessage,
},
data() {
const schema = yup.object().shape({
username: yup.string().required("Username is required!"),
password: yup.string().required("Password is required!"),
});
return {
loading: false,
message: "",
schema,
};
},
computed: {
loggedIn() {
return this.$store.state.auth.status.loggedIn;
},
},
created() {
if (this.loggedIn) {
this.$router.push("/profile");
}
},
methods: {
handleLogin(user) {
this.loading = true;
this.$store.dispatch("auth/login", user).then(
() => {
this.$router.push("/profile");
},
(error) => {
this.loading = false;
this.message =
(error.response &&
error.response.data &&
error.response.data.message) ||
error.message ||
error.toString();
}
);
},
},
};
</script>
<style scoped>
label {
display: block;
margin-top: 10px;
}
.card-container.card {
max-width: 350px !important;
padding: 40px 40px;
}
.card {
background-color: #f7f7f7;
padding: 20px 25px 30px;
margin: 0 auto 25px;
margin-top: 50px;
-moz-border-radius: 2px;
-webkit-border-radius: 2px;
border-radius: 2px;
-moz-box-shadow: 0px 2px 2px rgba(0, 0, 0, 0.3);
-webkit-box-shadow: 0px 2px 2px rgba(0, 0, 0, 0.3);
box-shadow: 0px 2px 2px rgba(0, 0, 0, 0.3);
}
.profile-img-card {
width: 96px;
height: 96px;
margin: 0 auto 10px;
display: block;
-moz-border-radius: 50%;
-webkit-border-radius: 50%;
border-radius: 50%;
}
.error-feedback {
color: red;
}
</style>
================================================
FILE: src/components/Profile.vue
================================================
<template>
<div class="container">
<header class="jumbotron">
<h3>
<strong>{{currentUser.username}}</strong> Profile
</h3>
</header>
<p>
<strong>Token:</strong>
{{currentUser.accessToken.substring(0, 20)}} ... {{currentUser.accessToken.substr(currentUser.accessToken.length - 20)}}
</p>
<p>
<strong>Id:</strong>
{{currentUser.id}}
</p>
<p>
<strong>Email:</strong>
{{currentUser.email}}
</p>
<strong>Authorities:</strong>
<ul>
<li v-for="role in currentUser.roles" :key="role">{{role}}</li>
</ul>
</div>
</template>
<script>
export default {
name: 'Profile',
computed: {
currentUser() {
return this.$store.state.auth.user;
}
},
mounted() {
if (!this.currentUser) {
this.$router.push('/login');
}
}
};
</script>
================================================
FILE: src/components/Register.vue
================================================
<template>
<div class="col-md-12">
<div class="card card-container">
<img
id="profile-img"
src="//ssl.gstatic.com/accounts/ui/avatar_2x.png"
class="profile-img-card"
/>
<Form @submit="handleRegister" :validation-schema="schema">
<div v-if="!successful">
<div class="form-group">
<label for="username">Username</label>
<Field name="username" type="text" class="form-control" />
<ErrorMessage name="username" class="error-feedback" />
</div>
<div class="form-group">
<label for="email">Email</label>
<Field name="email" type="email" class="form-control" />
<ErrorMessage name="email" class="error-feedback" />
</div>
<div class="form-group">
<label for="password">Password</label>
<Field name="password" type="password" class="form-control" />
<ErrorMessage name="password" class="error-feedback" />
</div>
<div class="form-group">
<button class="btn btn-primary btn-block" :disabled="loading">
<span
v-show="loading"
class="spinner-border spinner-border-sm"
></span>
Sign Up
</button>
</div>
</div>
</Form>
<div
v-if="message"
class="alert"
:class="successful ? 'alert-success' : 'alert-danger'"
>
{{ message }}
</div>
</div>
</div>
</template>
<script>
import { Form, Field, ErrorMessage } from "vee-validate";
import * as yup from "yup";
export default {
name: "Register",
components: {
Form,
Field,
ErrorMessage,
},
data() {
const schema = yup.object().shape({
username: yup
.string()
.required("Username is required!")
.min(3, "Must be at least 3 characters!")
.max(20, "Must be maximum 20 characters!"),
email: yup
.string()
.required("Email is required!")
.email("Email is invalid!")
.max(50, "Must be maximum 50 characters!"),
password: yup
.string()
.required("Password is required!")
.min(6, "Must be at least 6 characters!")
.max(40, "Must be maximum 40 characters!"),
});
return {
successful: false,
loading: false,
message: "",
schema,
};
},
computed: {
loggedIn() {
return this.$store.state.auth.status.loggedIn;
},
},
mounted() {
if (this.loggedIn) {
this.$router.push("/profile");
}
},
methods: {
handleRegister(user) {
this.message = "";
this.successful = false;
this.loading = true;
this.$store.dispatch("auth/register", user).then(
(data) => {
this.message = data.message;
this.successful = true;
this.loading = false;
},
(error) => {
this.message =
(error.response &&
error.response.data &&
error.response.data.message) ||
error.message ||
error.toString();
this.successful = false;
this.loading = false;
}
);
},
},
};
</script>
<style scoped>
label {
display: block;
margin-top: 10px;
}
.card-container.card {
max-width: 350px !important;
padding: 40px 40px;
}
.card {
background-color: #f7f7f7;
padding: 20px 25px 30px;
margin: 0 auto 25px;
margin-top: 50px;
-moz-border-radius: 2px;
-webkit-border-radius: 2px;
border-radius: 2px;
-moz-box-shadow: 0px 2px 2px rgba(0, 0, 0, 0.3);
-webkit-box-shadow: 0px 2px 2px rgba(0, 0, 0, 0.3);
box-shadow: 0px 2px 2px rgba(0, 0, 0, 0.3);
}
.profile-img-card {
width: 96px;
height: 96px;
margin: 0 auto 10px;
display: block;
-moz-border-radius: 50%;
-webkit-border-radius: 50%;
border-radius: 50%;
}
.error-feedback {
color: red;
}
</style>
================================================
FILE: src/main.js
================================================
import { createApp } from "vue";
import App from "./App.vue";
import router from "./router";
import store from "./store";
import "bootstrap";
import "bootstrap/dist/css/bootstrap.min.css";
import { FontAwesomeIcon } from './plugins/font-awesome'
createApp(App)
.use(router)
.use(store)
.component("font-awesome-icon", FontAwesomeIcon)
.mount("#app");
================================================
FILE: src/plugins/font-awesome.js
================================================
import { library } from "@fortawesome/fontawesome-svg-core";
import { FontAwesomeIcon } from "@fortawesome/vue-fontawesome";
import {
faHome,
faUser,
faUserPlus,
faSignInAlt,
faSignOutAlt,
} from "@fortawesome/free-solid-svg-icons";
library.add(faHome, faUser, faUserPlus, faSignInAlt, faSignOutAlt);
export { FontAwesomeIcon };
================================================
FILE: src/router.js
================================================
import { createWebHistory, createRouter } from "vue-router";
import Home from "./components/Home.vue";
import Login from "./components/Login.vue";
import Register from "./components/Register.vue";
// lazy-loaded
const Profile = () => import("./components/Profile.vue")
const BoardAdmin = () => import("./components/BoardAdmin.vue")
const BoardModerator = () => import("./components/BoardModerator.vue")
const BoardUser = () => import("./components/BoardUser.vue")
const routes = [
{
path: "/",
name: "home",
component: Home,
},
{
path: "/home",
component: Home,
},
{
path: "/login",
component: Login,
},
{
path: "/register",
component: Register,
},
{
path: "/profile",
name: "profile",
// lazy-loaded
component: Profile,
},
{
path: "/admin",
name: "admin",
// lazy-loaded
component: BoardAdmin,
},
{
path: "/mod",
name: "moderator",
// lazy-loaded
component: BoardModerator,
},
{
path: "/user",
name: "user",
// lazy-loaded
component: BoardUser,
},
];
const router = createRouter({
history: createWebHistory(),
routes,
});
// router.beforeEach((to, from, next) => {
// const publicPages = ['/login', '/register', '/home'];
// const authRequired = !publicPages.includes(to.path);
// const loggedIn = localStorage.getItem('user');
// // trying to access a restricted page + not logged in
// // redirect to login page
// if (authRequired && !loggedIn) {
// next('/login');
// } else {
// next();
// }
// });
export default router;
================================================
FILE: src/services/auth-header.js
================================================
export default function authHeader() {
let user = JSON.parse(localStorage.getItem('user'));
if (user && user.accessToken) {
return { Authorization: 'Bearer ' + user.accessToken }; // for Spring Boot back-end
// return { 'x-access-token': user.accessToken }; // for Node.js Express back-end
} else {
return {};
}
}
================================================
FILE: src/services/auth.service.js
================================================
import axios from 'axios';
const API_URL = 'http://localhost:8080/api/auth/';
class AuthService {
login(user) {
return axios
.post(API_URL + 'signin', {
username: user.username,
password: user.password
})
.then(response => {
if (response.data.accessToken) {
localStorage.setItem('user', JSON.stringify(response.data));
}
return response.data;
});
}
logout() {
localStorage.removeItem('user');
}
register(user) {
return axios.post(API_URL + 'signup', {
username: user.username,
email: user.email,
password: user.password
});
}
}
export default new AuthService();
================================================
FILE: src/services/user.service.js
================================================
import axios from 'axios';
import authHeader from './auth-header';
const API_URL = 'http://localhost:8080/api/test/';
class UserService {
getPublicContent() {
return axios.get(API_URL + 'all');
}
getUserBoard() {
return axios.get(API_URL + 'user', { headers: authHeader() });
}
getModeratorBoard() {
return axios.get(API_URL + 'mod', { headers: authHeader() });
}
getAdminBoard() {
return axios.get(API_URL + 'admin', { headers: authHeader() });
}
}
export default new UserService();
================================================
FILE: src/store/auth.module.js
================================================
import AuthService from '../services/auth.service';
const user = JSON.parse(localStorage.getItem('user'));
const initialState = user
? { status: { loggedIn: true }, user }
: { status: { loggedIn: false }, user: null };
export const auth = {
namespaced: true,
state: initialState,
actions: {
login({ commit }, user) {
return AuthService.login(user).then(
user => {
commit('loginSuccess', user);
return Promise.resolve(user);
},
error => {
commit('loginFailure');
return Promise.reject(error);
}
);
},
logout({ commit }) {
AuthService.logout();
commit('logout');
},
register({ commit }, user) {
return AuthService.register(user).then(
response => {
commit('registerSuccess');
return Promise.resolve(response.data);
},
error => {
commit('registerFailure');
return Promise.reject(error);
}
);
}
},
mutations: {
loginSuccess(state, user) {
state.status.loggedIn = true;
state.user = user;
},
loginFailure(state) {
state.status.loggedIn = false;
state.user = null;
},
logout(state) {
state.status.loggedIn = false;
state.user = null;
},
registerSuccess(state) {
state.status.loggedIn = false;
},
registerFailure(state) {
state.status.loggedIn = false;
}
}
};
================================================
FILE: src/store/index.js
================================================
import { createStore } from "vuex";
import { auth } from "./auth.module";
const store = createStore({
modules: {
auth,
},
});
export default store;
================================================
FILE: vue.config.js
================================================
module.exports = {
devServer: {
port: 8081
}
}
gitextract__tosskch/ ├── .gitignore ├── README.md ├── babel.config.js ├── package.json ├── public/ │ └── index.html ├── src/ │ ├── App.vue │ ├── components/ │ │ ├── BoardAdmin.vue │ │ ├── BoardModerator.vue │ │ ├── BoardUser.vue │ │ ├── Home.vue │ │ ├── Login.vue │ │ ├── Profile.vue │ │ └── Register.vue │ ├── main.js │ ├── plugins/ │ │ └── font-awesome.js │ ├── router.js │ ├── services/ │ │ ├── auth-header.js │ │ ├── auth.service.js │ │ └── user.service.js │ └── store/ │ ├── auth.module.js │ └── index.js └── vue.config.js
SYMBOL INDEX (20 symbols across 4 files)
FILE: src/services/auth-header.js
function authHeader (line 1) | function authHeader() {
FILE: src/services/auth.service.js
constant API_URL (line 3) | const API_URL = 'http://localhost:8080/api/auth/';
class AuthService (line 5) | class AuthService {
method login (line 6) | login(user) {
method logout (line 21) | logout() {
method register (line 25) | register(user) {
FILE: src/services/user.service.js
constant API_URL (line 4) | const API_URL = 'http://localhost:8080/api/test/';
class UserService (line 6) | class UserService {
method getPublicContent (line 7) | getPublicContent() {
method getUserBoard (line 11) | getUserBoard() {
method getModeratorBoard (line 15) | getModeratorBoard() {
method getAdminBoard (line 19) | getAdminBoard() {
FILE: src/store/auth.module.js
method login (line 12) | login({ commit }, user) {
method logout (line 24) | logout({ commit }) {
method register (line 28) | register({ commit }, user) {
method loginSuccess (line 42) | loginSuccess(state, user) {
method loginFailure (line 46) | loginFailure(state) {
method logout (line 50) | logout(state) {
method registerSuccess (line 54) | registerSuccess(state) {
method registerFailure (line 57) | registerFailure(state) {
Condensed preview — 22 files, each showing path, character count, and a content snippet. Download the .json file or copy for the full structured content (26K chars).
[
{
"path": ".gitignore",
"chars": 231,
"preview": ".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*\nyar"
},
{
"path": "README.md",
"chars": 3020,
"preview": "# Vue 3 Authentication with JWT, Vuex and Vue Router\n\n## Flow for User Registration and User Login\n\n![vue-3-authenticati"
},
{
"path": "babel.config.js",
"chars": 73,
"preview": "module.exports = {\n presets: [\n '@vue/cli-plugin-babel/preset'\n ]\n}\n"
},
{
"path": "package.json",
"chars": 1225,
"preview": "{\n \"name\": \"vue-3-authentication-jwt\",\n \"version\": \"0.1.0\",\n \"private\": true,\n \"scripts\": {\n \"serve\": \"vue-cli-se"
},
{
"path": "public/index.html",
"chars": 611,
"preview": "<!DOCTYPE html>\n<html lang=\"\">\n <head>\n <meta charset=\"utf-8\">\n <meta http-equiv=\"X-UA-Compatible\" content=\"IE=ed"
},
{
"path": "src/App.vue",
"chars": 2395,
"preview": "<template>\n <div id=\"app\">\n <nav class=\"navbar navbar-expand navbar-dark bg-dark\">\n <a href=\"/\" class=\"navbar-b"
},
{
"path": "src/components/BoardAdmin.vue",
"chars": 643,
"preview": "<template>\n <div class=\"container\">\n <header class=\"jumbotron\">\n <h3>{{ content }}</h3>\n </header>\n </div>\n"
},
{
"path": "src/components/BoardModerator.vue",
"chars": 651,
"preview": "<template>\n <div class=\"container\">\n <header class=\"jumbotron\">\n <h3>{{ content }}</h3>\n </header>\n </div>\n"
},
{
"path": "src/components/BoardUser.vue",
"chars": 641,
"preview": "<template>\n <div class=\"container\">\n <header class=\"jumbotron\">\n <h3>{{ content }}</h3>\n </header>\n </div>\n"
},
{
"path": "src/components/Home.vue",
"chars": 645,
"preview": "<template>\n <div class=\"container\">\n <header class=\"jumbotron\">\n <h3>{{ content }}</h3>\n </header>\n </div>\n"
},
{
"path": "src/components/Login.vue",
"chars": 3073,
"preview": "<template>\n <div class=\"col-md-12\">\n <div class=\"card card-container\">\n <img\n id=\"profile-img\"\n s"
},
{
"path": "src/components/Profile.vue",
"chars": 858,
"preview": "<template>\n <div class=\"container\">\n <header class=\"jumbotron\">\n <h3>\n <strong>{{currentUser.username}}<"
},
{
"path": "src/components/Register.vue",
"chars": 3976,
"preview": "<template>\n <div class=\"col-md-12\">\n <div class=\"card card-container\">\n <img\n id=\"profile-img\"\n s"
},
{
"path": "src/main.js",
"chars": 360,
"preview": "import { createApp } from \"vue\";\nimport App from \"./App.vue\";\nimport router from \"./router\";\nimport store from \"./store\""
},
{
"path": "src/plugins/font-awesome.js",
"chars": 341,
"preview": "import { library } from \"@fortawesome/fontawesome-svg-core\";\nimport { FontAwesomeIcon } from \"@fortawesome/vue-fontaweso"
},
{
"path": "src/router.js",
"chars": 1592,
"preview": "import { createWebHistory, createRouter } from \"vue-router\";\nimport Home from \"./components/Home.vue\";\nimport Login from"
},
{
"path": "src/services/auth-header.js",
"chars": 341,
"preview": "export default function authHeader() {\n let user = JSON.parse(localStorage.getItem('user'));\n\n if (user && user.access"
},
{
"path": "src/services/auth.service.js",
"chars": 688,
"preview": "import axios from 'axios';\n\nconst API_URL = 'http://localhost:8080/api/auth/';\n\nclass AuthService {\n login(user) {\n "
},
{
"path": "src/services/user.service.js",
"chars": 522,
"preview": "import axios from 'axios';\nimport authHeader from './auth-header';\n\nconst API_URL = 'http://localhost:8080/api/test/';\n\n"
},
{
"path": "src/store/auth.module.js",
"chars": 1463,
"preview": "import AuthService from '../services/auth.service';\n\nconst user = JSON.parse(localStorage.getItem('user'));\nconst initia"
},
{
"path": "src/store/index.js",
"chars": 158,
"preview": "import { createStore } from \"vuex\";\nimport { auth } from \"./auth.module\";\n\nconst store = createStore({\n modules: {\n "
},
{
"path": "vue.config.js",
"chars": 54,
"preview": "module.exports = {\n devServer: {\n port: 8081\n }\n}"
}
]
About this extraction
This page contains the full source code of the bezkoder/vue-3-authentication-jwt GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 22 files (23.0 KB), approximately 6.6k tokens, and a symbol index with 20 extracted functions, classes, methods, constants, and types. Use this with OpenClaw, Claude, ChatGPT, Cursor, Windsurf, or any other AI tool that accepts text input. You can copy the full output to your clipboard or download it as a .txt file.
Extracted by GitExtract — free GitHub repo to text converter for AI. Built by Nikandr Surkov.