My current project involves utilizing NUXT 3 for the frontend and integrating Wordpress as the backend. The data is transmitted from the backend to the frontend through the REST API. The application functions as a content management system (CMS), with all routes protected by a middleware that verifies the user's login status. This middleware checks for the existence of local storage, created upon successful user login.
The process works as follows:
For every route, the middleware validates the presence of local storage userAuthentication. If it's missing, the user is redirected to the /login page. This middleware operates globally but only on the client side.
Upon attempting to access the application, a POST request is sent to the Wordpress backend with the user's provided credentials. If the endpoint responds with CODE 200, the data is saved in the PINIA store, and a local storage is generated containing the response data (including the token). Subsequently, the user gains access to protected routes.
When the user logs out, the local storage is deleted, and they are redirected to the /login page.
Here are some queries I have:
- Is this approach secure?
- Is the server adequately secured by Wordpress, or should I implement server middleware?
- Could an unauthorized individual gain access to my app by creating local storage with the same name?
I welcome any insights or suggestions.
middleware/auth.global.ts
export default defineNuxtRouteMiddleware((to, from) => {
// isAuthenticated() serves as an example validation method for user authentication
if (typeof window !== 'undefined') {
const useStateLocalStorage = JSON.parse(localStorage.getItem('userAuthentication'));
if (!useStateLocalStorage) {
if (from.path === '/login') {
return abortNavigation()
}
if (to.path !== '/login') {
return navigateTo('/login')
}
}
if (useStateLocalStorage) {
if (to.path === '/login') {
return abortNavigation()
}
}
}
})
/login.vue
import { useUserStore } from "~/store/userAuth";
const config = useRuntimeConfig();
const signinForm = ref({ username: "", password: "" });
const userStore = useUserStore();
const signIn = async () => {
const response = await $fetch(config.public.apiBaseUrl + '/wp-json/jwt-auth/v1/token',
{
method: "post",
body: {
'username': signinForm.value.username,
'password': signinForm.value.password
}
})
.then((response) => {
//SUCCESS
//console.log('LOGIN SUCCESS', response);
//SAVE USER DATA IN PINIA STORE
userStore.IsAuth = true;
userStore.token = response['data']['token'];
userStore.username = response['data']['displayName'];
userStore.email = response['data']['email'];
userStore.firstName = response['data']['firstName'];
userStore.lastName = response['data']['lastName'];
//DEBUG
console.log(userStore.IsAuth)
console.log(userStore.token)
console.log(userStore.username)
console.log(userStore.email)
console.log(userStore.firstName)
console.log(userStore.lastName)
//NAVIGATE TO HOME
navigateTo('/')
})
.catch((error) => {
console.log('LOGIN ERROR', error)
});
//console.log(response)
signinForm.value = {username: "", password: ""};
}
userStore.$subscribe((mutation, state) => {
localStorage.setItem('userAuthentication', JSON.stringify(state))
})
store/userAuth.js
import { defineStore } from 'pinia'
export const useUserStore = defineStore('user', {
state: () => {
return {
token: null,
username: null,
email: null,
firstName: null,
lastName: null,
IsAuth: false
}
},
persist: true,
actions: {
userUpdate(payload) {
//localStorage.setItem('user-auth', payload)
this.user = payload;
this.IsAuth = payload;
},
tokenUpdate(payload) {
//localStorage.setItem('user-auth', payload)
this.token = payload;
},
}
})