Architecture Overview
To enhance session security and manage user persistence, the architecture employs a pair of JSON Web Tokens (JWT). An access_token handles immediate API requests with a short lifespan (e.g., 30 minutes), while a refresh_token maintains longer-term validity (e.g., 60 minutes) to extend sessions without re-authentication. When the access token expires, the client automatically invokes the refresh endpoint. Successful renewal provides new credentials; failure triggers a forced logout.
Frontend Token Handling via Axios
The Vue frontend initializes an Axios instance configured to intercept all network traffic. Headers for user identity and the current access token are attached before every request. Upon receiving an HTTP response, the system validates the status code. Specific error codes indicating authentication failures trigger the refresh logic asynchronously.
import axios from 'axios';
import authStore from '@/store/auth';
const apiClient = axios.create({
baseURL: '/api',
timeout: 60000,
headers: { 'Content-Type': 'application/json' }
});
apiClient.interceptors.request.use((config) => {
const currentUser = authStore.getters.activeUser;
if (currentUser && currentUser.accessToken) {
config.headers['Authorization'] = `Bearer ${currentUser.accessToken}`;
config.headers['X-User-Name'] = currentUser.userName;
}
return config;
});
apiClient.interceptors.response.use(
(response) => response,
async (error) => {
const { config, response } = error;
// Detect unauthorized errors (e.g., token expired)
if (response && (response.status === 401 || response?.data?.code === '4001')) {
if (!config.__retryCount) {
config.__retryCount = 1;
try {
await authStore.dispatch('refreshToken');
const updatedUser = authStore.getters.activeUser;
// Reattach new tokens and retry original request
config.headers['Authorization'] = `Bearer ${updatedUser.accessToken}`;
config.headers['X-User-Name'] = updatedUser.userName;
return apiClient(config);
} catch (refreshError) {
// Refresh failed, clear session
await authStore.dispatch('logout');
window.location.reload();
return Promise.reject(refreshError);
}
}
}
return Promise.reject(error);
}
);
export default apiClient;
Vuex Store Integration
Application state manages the active session. Cookies synchronize initial load state, ensuring SSR compatibility if needed.
import Vue from 'vue';
import Vuex from 'vuex';
import Cookies from 'js-cookie';
Vue.use(Vuex);
export default new Vuex.Store({
state: {
activeUser: Cookies.get('user') ? JSON.parse(Cookies.get('user')) : null
},
getters: {
isAuthenticated: (state) => !!state.activeUser,
activeUser: (state) => state.activeUser
},
actions: {
refreshToken(context) {
return new Promise(async (resolve, reject) => {
// Implement backend refresh call here
// ...
});
},
logout({ commit }) {
Cookies.remove('user');
commit('SET_USER', null);
}
}
});
Operational Logic
On successful refresh, the application updates the stored credentials and proceeds silently. If the refresh attempt fails, the system assumes the user account is compromised or revoked, clearing local storage and redirecting to the login view by reloading the page.