From 1ab7e7e105083e15e732a8fdbcdfaeceda8cd844 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bjo=CC=88rn=20Fromme?= Date: Thu, 3 Oct 2019 18:20:42 +0200 Subject: [PATCH] Implement token refreshing --- package-lock.json | 8 ++ package.json | 1 + .../Resources/Private/Assets/js/api/index.js | 91 ++++--------------- .../Private/Assets/js/myep/Address.vue | 6 +- .../Resources/Private/Assets/js/myep/App.vue | 1 - .../Private/Assets/js/myep/CrmData.vue | 15 +-- .../Private/Assets/js/myep/Events.vue | 14 +-- .../Private/Assets/js/myep/Newsletter.vue | 12 +-- .../Private/Assets/js/myep/Teamer.vue | 15 +-- .../Private/Assets/js/store/index.js | 44 ++++----- 10 files changed, 64 insertions(+), 143 deletions(-) diff --git a/package-lock.json b/package-lock.json index 9e584981..d9231c7a 100644 --- a/package-lock.json +++ b/package-lock.json @@ -528,6 +528,14 @@ "is-buffer": "^2.0.2" } }, + "axios-auth-refresh": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/axios-auth-refresh/-/axios-auth-refresh-1.0.7.tgz", + "integrity": "sha512-TQl1tF+MY+iDG93WpiqcnwGb1lvdJLKzi0IN/7hBkYFlpOC6xv4S+cW3QHZOBjKpFWRWqHg9fXd/PDsCvJ3uLA==", + "requires": { + "axios": "^0.18.0" + } + }, "babel-code-frame": { "version": "6.26.0", "resolved": "https://registry.npmjs.org/babel-code-frame/-/babel-code-frame-6.26.0.tgz", diff --git a/package.json b/package.json index 2151b2bc..44663abe 100644 --- a/package.json +++ b/package.json @@ -12,6 +12,7 @@ "dependencies": { "@fancyapps/fancybox": "^3.5.7", "axios": "^0.18.0", + "axios-auth-refresh": "^1.0.7", "bootstrap-sass": "^3.4.1", "bourbon": "^4.3.2", "cookieconsent": "^3.1.0", diff --git a/public/typo3conf/ext/ep_theme/Resources/Private/Assets/js/api/index.js b/public/typo3conf/ext/ep_theme/Resources/Private/Assets/js/api/index.js index 12f1a1c8..bb8827ee 100644 --- a/public/typo3conf/ext/ep_theme/Resources/Private/Assets/js/api/index.js +++ b/public/typo3conf/ext/ep_theme/Resources/Private/Assets/js/api/index.js @@ -1,77 +1,26 @@ -// See https://www.techynovice.com/setting-up-JWT-token-refresh-mechanism-with-axios/ +import axios from 'axios' +import createAuthRefreshInterceptor from 'axios-auth-refresh' -import axios from 'axios'; +const authenticatedClient = axios.create(); -const authenticatedClient = axios.create({ - headers: { - 'Authentication': 'Bearer ' + sessionStorage.getItem('token') - } +const getAccessToken = () => { + return sessionStorage.getItem('token'); +}; + +authenticatedClient.interceptors.request.use(request => { + request.headers['Authorization'] = 'Bearer ' + getAccessToken(); + return request; }); -authenticatedClient.interceptors.response.use( - response => response, - error => { - const errorResponse = error.response; - if (isTokenExpiredError(errorResponse)) { - return resetTokenAndReattemptRequest(error) - } - return Promise.reject(error) - } -); +const refreshAuth = failedRequest => axios.post('/api/token_refresh', { + refresh_token: sessionStorage.getItem('refreshToken') + }).then(response => { + sessionStorage.setItem('token', response.data.token); + sessionStorage.setItem('refreshToken', response.data.refresh_token); + failedRequest.response.config.headers['Authorization'] = 'Bearer ' + response.data.token; + return Promise.resolve(); + }); -function isTokenExpiredError (errorResponse) { - if (errorResponse.config.code !== 401) { - return false - } +createAuthRefreshInterceptor(authenticatedClient, refreshAuth); - return errorResponse.message.match(/expired/); -} - -let isAlreadyFetchingAccessToken = false; -let subscribers = []; - -async function resetTokenAndReattemptRequest (error) { - try { - const { response: errorResponse } = error; - const refreshToken = await getRefreshToken(); - if (!refreshToken) { - return Promise.reject(error); - } - const retryOriginalRequest = new Promise(resolve => { - addSubscriber(authToken => { - errorResponse.config.headers.Authorization = 'Bearer ' + authToken; - resolve(axios(errorResponse.config)); - }); - }); - if (!isAlreadyFetchingAccessToken) { - isAlreadyFetchingAccessToken = true; - axios({ - method: 'post', - url: ``, - data: { - refresh_token: refreshToken - } - }).then(response => { - if (!response.data) { - return Promise.reject(error); - } - const newToken = response.data.refresh_token; - saveRefreshToken(newToken); - isAlreadyFetchingAccessToken = false; - onAccessTokenFetched(newToken); - }); - } - return retryOriginalRequest; - } catch (err) { - return Promise.reject(err); - } -} - -function onAccessTokenFetched(access_token) { - subscribers.forEach(callback => callback(access_token)); - subscribers = []; -} - -function addSubscriber(callback) { - subscribers.push(callback); -} +export default authenticatedClient diff --git a/public/typo3conf/ext/ep_theme/Resources/Private/Assets/js/myep/Address.vue b/public/typo3conf/ext/ep_theme/Resources/Private/Assets/js/myep/Address.vue index 36d67fc5..00d8e82f 100644 --- a/public/typo3conf/ext/ep_theme/Resources/Private/Assets/js/myep/Address.vue +++ b/public/typo3conf/ext/ep_theme/Resources/Private/Assets/js/myep/Address.vue @@ -65,10 +65,10 @@ diff --git a/public/typo3conf/ext/ep_theme/Resources/Private/Assets/js/myep/Events.vue b/public/typo3conf/ext/ep_theme/Resources/Private/Assets/js/myep/Events.vue index 3fcb2a7a..1b13ac15 100644 --- a/public/typo3conf/ext/ep_theme/Resources/Private/Assets/js/myep/Events.vue +++ b/public/typo3conf/ext/ep_theme/Resources/Private/Assets/js/myep/Events.vue @@ -43,7 +43,7 @@ diff --git a/public/typo3conf/ext/ep_theme/Resources/Private/Assets/js/myep/Newsletter.vue b/public/typo3conf/ext/ep_theme/Resources/Private/Assets/js/myep/Newsletter.vue index 34dcb854..7c77b41a 100644 --- a/public/typo3conf/ext/ep_theme/Resources/Private/Assets/js/myep/Newsletter.vue +++ b/public/typo3conf/ext/ep_theme/Resources/Private/Assets/js/myep/Newsletter.vue @@ -16,7 +16,7 @@