How to refresh JWT tokens in Vue
Refreshing JWT tokens in Vue applications ensures continuous user authentication without forcing re-login when access tokens expire. As the creator of CoreUI with extensive Vue development experience since 2014, I’ve implemented token refresh systems in numerous production applications for seamless user experience. The most reliable approach uses axios interceptors to automatically refresh expired tokens and retry failed requests. This pattern provides transparent authentication management while maintaining security through short-lived access tokens.
Use axios interceptors with Pinia store to automatically refresh JWT tokens when they expire.
// stores/auth.js
import { defineStore } from 'pinia'
import axios from 'axios'
export const useAuthStore = defineStore('auth', {
state: () => ({
accessToken: null,
refreshToken: localStorage.getItem('refreshToken'),
user: null
}),
actions: {
async refreshAccessToken() {
try {
const response = await axios.post('/api/auth/refresh', {
refreshToken: this.refreshToken
})
this.accessToken = response.data.accessToken
if (response.data.refreshToken) {
this.refreshToken = response.data.refreshToken
localStorage.setItem('refreshToken', response.data.refreshToken)
}
return response.data.accessToken
} catch (error) {
this.logout()
throw error
}
},
logout() {
this.accessToken = null
this.refreshToken = null
this.user = null
localStorage.removeItem('refreshToken')
}
}
})
// axios-interceptor.js
import axios from 'axios'
import { useAuthStore } from '@/stores/auth'
let isRefreshing = false
let failedQueue = []
axios.interceptors.response.use(
response => response,
async error => {
const authStore = useAuthStore()
if (error.response?.status === 401 && authStore.refreshToken) {
if (!isRefreshing) {
isRefreshing = true
try {
const newToken = await authStore.refreshAccessToken()
// Retry all failed requests
failedQueue.forEach(({ resolve, config }) => {
config.headers.Authorization = `Bearer ${newToken}`
resolve(axios(config))
})
failedQueue = []
// Retry original request
error.config.headers.Authorization = `Bearer ${newToken}`
return axios(error.config)
} catch (refreshError) {
failedQueue = []
return Promise.reject(refreshError)
} finally {
isRefreshing = false
}
} else {
// Queue failed requests while refreshing
return new Promise(resolve => {
failedQueue.push({ resolve, config: error.config })
})
}
}
return Promise.reject(error)
}
)
This code implements automatic token refresh using axios interceptors that detect 401 responses and attempt to refresh the access token. When multiple requests fail simultaneously, they’re queued and retried after successful token refresh. The Pinia store manages token state and provides centralized refresh logic with proper error handling.
Best Practice Note:
This is the token refresh architecture we use in CoreUI Vue enterprise applications for secure, uninterrupted user sessions. Always implement proper queue management to prevent multiple concurrent refresh attempts and ensure failed requests are retried correctly.



