2016-08-08 00:47:58 +05:30
|
|
|
import authentication from 'services/api/authentication';
|
|
|
|
import {updateUser, logout} from '../actions';
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Ensures, that all user's requests have fresh access token
|
|
|
|
*
|
|
|
|
* @param {object} store - redux store
|
|
|
|
* @param {function} store.getState
|
|
|
|
* @param {function} store.dispatch
|
|
|
|
*
|
|
|
|
* @return {object} - request middleware
|
|
|
|
*/
|
|
|
|
export default function refreshTokenMiddleware({dispatch, getState}) {
|
|
|
|
return {
|
|
|
|
before(data) {
|
2016-08-11 00:59:16 +05:30
|
|
|
const {refreshToken, token} = getState().user;
|
2016-08-08 00:47:58 +05:30
|
|
|
const isRefreshTokenRequest = data.url.includes('refresh-token');
|
|
|
|
|
2016-08-11 00:59:16 +05:30
|
|
|
if (!token || isRefreshTokenRequest) {
|
2016-08-08 00:47:58 +05:30
|
|
|
return data;
|
|
|
|
}
|
|
|
|
|
2016-08-11 00:59:16 +05:30
|
|
|
try {
|
|
|
|
const SAFETY_FACTOR = 60; // ask new token earlier to overcome time dissynchronization problem
|
|
|
|
const jwt = getJWTPayload(token);
|
2016-08-08 00:47:58 +05:30
|
|
|
|
2016-08-11 00:59:16 +05:30
|
|
|
if (jwt.exp - SAFETY_FACTOR < Date.now() / 1000) {
|
|
|
|
return requestAccessToken(refreshToken, dispatch).then(() => data);
|
|
|
|
}
|
|
|
|
} catch (err) {
|
|
|
|
dispatch(logout());
|
2016-08-08 00:47:58 +05:30
|
|
|
}
|
|
|
|
|
|
|
|
return data;
|
|
|
|
},
|
|
|
|
|
|
|
|
catch(resp, restart) {
|
|
|
|
/*
|
|
|
|
{
|
|
|
|
"name": "Unauthorized",
|
|
|
|
"message": "You are requesting with an invalid credential.",
|
|
|
|
"code": 0,
|
|
|
|
"status": 401,
|
|
|
|
"type": "yii\\web\\UnauthorizedHttpException"
|
|
|
|
}
|
|
|
|
{
|
|
|
|
"name": "Unauthorized",
|
|
|
|
"message": "Token expired",
|
|
|
|
"code": 0,
|
|
|
|
"status": 401,
|
|
|
|
"type": "yii\\web\\UnauthorizedHttpException"
|
|
|
|
}
|
|
|
|
*/
|
|
|
|
if (resp && resp.status === 401) {
|
|
|
|
const {refreshToken} = getState().user;
|
|
|
|
if (resp.message === 'Token expired' && refreshToken) {
|
|
|
|
// request token and retry
|
|
|
|
return requestAccessToken(refreshToken, dispatch).then(restart);
|
|
|
|
}
|
|
|
|
|
|
|
|
dispatch(logout());
|
|
|
|
}
|
|
|
|
|
|
|
|
return Promise.reject(resp);
|
|
|
|
}
|
|
|
|
};
|
|
|
|
}
|
|
|
|
|
|
|
|
function requestAccessToken(refreshToken, dispatch) {
|
|
|
|
let promise;
|
|
|
|
if (refreshToken) {
|
2016-08-10 00:47:49 +05:30
|
|
|
promise = authentication.requestToken(refreshToken);
|
2016-08-08 00:47:58 +05:30
|
|
|
} else {
|
|
|
|
promise = Promise.reject();
|
|
|
|
}
|
|
|
|
|
|
|
|
return promise
|
2016-08-10 00:47:49 +05:30
|
|
|
.then(({token}) => dispatch(updateUser({
|
|
|
|
token
|
2016-08-08 00:47:58 +05:30
|
|
|
})))
|
|
|
|
.catch(() => dispatch(logout()));
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
function getJWTPayload(jwt) {
|
|
|
|
const parts = (jwt || '').split('.');
|
|
|
|
|
|
|
|
if (parts.length !== 3) {
|
|
|
|
throw new Error('Invalid jwt token');
|
|
|
|
}
|
|
|
|
|
|
|
|
try {
|
|
|
|
return JSON.parse(atob(parts[1]));
|
|
|
|
} catch (err) {
|
|
|
|
throw new Error('Can not decode jwt token');
|
|
|
|
}
|
|
|
|
}
|