All files / src/api axios.ts

0% Statements 0/42
0% Branches 0/1
0% Functions 0/1
0% Lines 0/42

Press n or j to go to the next uncovered block, b, p or k for the previous block.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60                                                                                                                       
import axios, { type AxiosError } from 'axios'
import { useKeycloak } from '@/composables/useKeycloak'
import { env } from '@/env'
 
const api = axios.create({
  baseURL: env.API_URL,
  timeout: 30000,
  headers: {
    'Content-Type': 'application/json',
  },
})
 
// Token from Keycloak automatically added to requests
api.interceptors.request.use(
  async (config) => {
    const keycloak = useKeycloak()
    const token = await keycloak.getAccessToken()
    
    if (token) {
      config.headers.Authorization = `Bearer ${token}`
    }
    return config
  },
  (error) => Promise.reject(error)
)
 
// Global error handling
api.interceptors.response.use(
  (response) => response,
  async (error: AxiosError) => {
    // 401: Not authenticated -> Try to refresh, then redirect to login
    if (error.response?.status === 401) {
      const keycloak = useKeycloak()
      
      // Try to ensure valid token (silent refresh)
      const hasValidToken = await keycloak.ensureValidToken()
      
      if (!hasValidToken) {
        // Clear any stored data
        localStorage.removeItem('user')
        
        // Redirect to login if not already there
        if (window.location.pathname !== '/login') {
          const returnUrl = window.location.pathname
          await keycloak.login(returnUrl)
        }
      }
    }
    
    // 403: Forbidden
    if (error.response?.status === 403) {
      console.error('Access forbidden:', error.response.data)
    }
    
    return Promise.reject(error)
  }
)
 
export default api