From 3bf02f16dcfbcb9c05b388309ada03580fc6c09c Mon Sep 17 00:00:00 2001 From: SleepWalker Date: Sat, 4 Jun 2016 17:58:29 +0300 Subject: [PATCH] #126: added refresh token support on frontend --- src/components/user/actions.js | 79 +++++++++++++++++++++--------- src/services/api/authentication.js | 7 +++ 2 files changed, 64 insertions(+), 22 deletions(-) diff --git a/src/components/user/actions.js b/src/components/user/actions.js index 05f82ea..d7a2578 100644 --- a/src/components/user/actions.js +++ b/src/components/user/actions.js @@ -54,24 +54,39 @@ export function logout() { } export function fetchUserData() { - return (dispatch) => + return (dispatch, getState) => accounts.current() - .then((resp) => { - dispatch(updateUser(resp)); + .then((resp) => { + dispatch(updateUser(resp)); - return dispatch(changeLang(resp.lang)); - }); - /* - .catch((resp) => { - { - "name": "Unauthorized", - "message": "You are requesting with an invalid credential.", - "code": 0, - "status": 401, - "type": "yii\\web\\UnauthorizedHttpException" - } - }); - */ + return dispatch(changeLang(resp.lang)); + }) + .catch((resp) => { + /* + { + "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 {token} = getState().user; + if (resp.message === 'Token expired' && token) { + return dispatch(authenticate(token)); + } + + dispatch(logout()); + } + }); } export function changePassword({ @@ -95,14 +110,20 @@ export function changePassword({ } -export function authenticate(token, refreshToken) { - if (!token || token.split('.').length !== 3) { - throw new Error('Invalid token'); - } +import authentication from 'services/api/authentication'; +export function authenticate(token, refreshToken) { // TODO: this action, probably, belongs to components/auth + const jwt = getJWTPayload(token); + + return (dispatch, getState) => { + refreshToken = refreshToken || getState().user.refreshToken; + + if (jwt.exp < Date.now() / 1000) { + return authentication.refreshToken(refreshToken) + .then((resp) => dispatch(authenticate(resp.access_token))) + .catch(() => dispatch(logout())); + } - return (dispatch) => { request.setAuthToken(token); - return dispatch(fetchUserData()).then((resp) => { dispatch(updateUser({ isGuest: false, @@ -113,3 +134,17 @@ export function authenticate(token, refreshToken) { }); }; } + +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'); + } +} diff --git a/src/services/api/authentication.js b/src/services/api/authentication.js index 90282cd..bea1019 100644 --- a/src/services/api/authentication.js +++ b/src/services/api/authentication.js @@ -10,5 +10,12 @@ export default { '/api/authentication/login', {login, password, rememberMe} ); + }, + + refreshToken(refresh_token) { + return request.post( + '/api/authentication/refresh-token', + {refresh_token} + ); } };