class ApiClass { constructor(){ this.onUnauthorized = null; this.baseUrl = (window.apiUrl && window.apiUrl !== '') ? window.apiUrl : "/api/v1.0"; /** * Allow this endpoint to run without authentication token * @type {string[]} */ this.allowedEndpoints = [ '/login', '/register', '/reset', '/password-reset-step2/', '/auth', '/oauth', '/oauth/token', '/oauth/authorize', '/oauth/scopes', '/api/v1.0/oauth', '/api/v1.0/oauth/token', '/api/v1.0/oauth/authorize', '/api/v1.0/oauth/scopes', '/auth/login', '/api/auth/login', ]; /** * Maximum allowed difference in token expiration time and now before refresh token task is fired * @type {number} */ this.maxTokenExpirationDiff = 24 * 60 * 60 * 1000; // 1 day this.axios = axios.create({ baseURL: this.baseUrl, }); this.initHeaders(); this.initInterceptors(); } /** * Setup global headers */ initHeaders(){ //this.axios.defaults.headers.common['X-Requested-With'] = 'XMLHttpRequest'; // we will send ajax requests // check if csrf token is set in app and add it to headers let token = document.head.querySelector('meta[name="csrf-token"]'); if( token ){ //this.axios.defaults.headers.common['X-CSRF-TOKEN'] = token.content; } // check if oauth token is set and add it to headers if( localStorage.oauth_access_token ) { this.axios.defaults.headers.common['Authorization'] = 'Bearer ' + localStorage.oauth_access_token; } } /** * Setup request and response interceptors */ initInterceptors(){ let $this = this; // request this.axios.interceptors.request.use(function (config) { let endpoint = config.url.replace(config.baseURL, ''); if( !$this.allowedEndpoints.find($this.isAllowedEndpoint(endpoint)) ) { return $this.checkToken() .then( () => { config.headers.Authorization = 'Bearer ' + localStorage.oauth_access_token; return config; }) .catch((error) => { //return Promise.reject("Endpoint is not allowed for unathoriszed user"); return Promise.reject("Endpoint is not allowed for unathoriszed user. " + error); }); }else { return config; } }, function (error) { return Promise.reject(error); }); // response this.axios.interceptors.response.use(function(response){ if( response ){ let endpoint = response.config.url.replace(response.config.baseURL, ''); if( endpoint === "/oauth" || endpoint === "/api/v1.0/oauth" || endpoint === "/oauth/token" || endpoint === '/api/oauth/token' || endpoint === '/auth/login' || endpoint === '/api/auth/login' ){ let now = new Date(); now.setSeconds( now.getSeconds() + (response.data.expires_in - (48 * 60 * 60) ) ); localStorage.oauth_access_token = response.data.access_token; localStorage.oauth_refresh_token = response.data.refresh_token; localStorage.oauth_expires = now.getTime(); $this.axios.defaults.headers.common['Authorization'] = 'Bearer ' + localStorage.oauth_access_token; } } return response; }, function (error) { if( error.response && error.response.status && error.response.status === 401 ){ if( typeof $this.onUnauthorized === 'function' ){ $this.clearToken(); $this.onUnauthorized(); } } return Promise.reject(error); }); } isAllowedEndpoint(endpoint){ return (element) => { return (endpoint.indexOf(element) === 0); } } checkToken(){ if( localStorage.oauth_access_token ) { if( localStorage.oauth_expires ){ let now = Date.now(); let diff = localStorage.oauth_expires - now; if( diff < this.maxTokenExpirationDiff ) { return this.refreshToken(); }else{ if( localStorage.oauth_access_token ) { this.axios.defaults.headers.common['Authorization'] = 'Bearer ' + localStorage.oauth_access_token; } return Promise.resolve(); } }else{ //return Promise.reject("There is no token expiration data."); return this.getToken(); } }else{ //return Promise.reject("There is no token. Authenticate first!"); return this.getToken(); } } getToken(){ return this.axios.post('/oauth', { client_id: "web", client_secret: "18E2E3BC396A7CCF9291D1B18EA6A33B76F18151", grant_type: "client_credentials" }); } refreshToken(){ return this.getToken(); //return this.axios.get("/token"); } clearToken(){ localStorage.removeItem('oauth_access_token'); localStorage.removeItem('oauth_refresh_token'); localStorage.removeItem('oauth_refresh_token'); } request(url){ return this.axios.request(url); } get(url, config){ return this.axios.get(url, config); } delete(url, config){ return this.axios.delete(url, config); } head(url, config){ return this.axios.head(url, config); } options(url, config){ return this.axios.options(url, config); } post(url, params, config){ return this.axios.post(url, params, config); } put(url, params, config){ return this.axios.put(url, params, config); } patch(url, params, config){ return this.axios.patch(url, params, config); } download(url, onProgress){ return this.axios.get(url, { responseType: 'blob', onDownloadProgress: onProgress, }).then( response => { if( response.headers['content-type'] === 'application/json' ) { let reader = new FileReader(); reader.onload = function(){ response.data = JSON.parse( reader.result ); }; reader.readAsText(response.data); return Promise.resolve( response ); }else{ let filename = 'file'; if (response.headers['content-disposition']) { let content_disposition = response.headers['content-disposition'].split(' '); for (let i = 0; i < content_disposition.length; i++) { if (content_disposition[i].indexOf('filename') > -1) { filename = content_disposition[i].split('=')[1]; } } } let blob = new Blob([response.data], {type: response.headers['content-type'] || 'application/octet-stream'}); if (typeof window.navigator.msSaveBlob !== 'undefined') { window.navigator.msSaveBlob(blob, filename); } else { var blobURL = window.URL.createObjectURL(blob); var tempLink = document.createElement('a'); tempLink.style.display = 'none'; tempLink.href = blobURL; tempLink.setAttribute('download', filename); if (typeof tempLink.download === 'undefined') { tempLink.setAttribute('target', '_blank'); } document.body.appendChild(tempLink); tempLink.click(); document.body.removeChild(tempLink); window.URL.revokeObjectURL(blobURL); } } }); } } window.API = new ApiClass();