diff --git a/src/common/auth/fetch_token.js b/src/common/auth/fetch_token.js index 6fe6933598cb..5384410fa7f8 100644 --- a/src/common/auth/fetch_token.js +++ b/src/common/auth/fetch_token.js @@ -8,6 +8,8 @@ export default function fetchToken(clientId, code) { body: data, }).then((resp) => { if (!resp.ok) throw new Error('Unable to fetch tokens'); - return resp.json(); + const tokens = resp.json(); + tokens.expires = (tokens.expires_in * 1000) + Date.now(); + return tokens; }); } diff --git a/src/common/auth/refresh_token.js b/src/common/auth/refresh_token.js index dabfbd358b81..d4b53264a411 100644 --- a/src/common/auth/refresh_token.js +++ b/src/common/auth/refresh_token.js @@ -8,6 +8,8 @@ export default function refreshAccessToken(clientId, refreshToken) { body: data, }).then((resp) => { if (!resp.ok) throw new Error('Unable to fetch tokens'); - return resp.json(); + const tokens = resp.json(); + tokens.expires = (tokens.expires_in * 1000) + Date.now(); + return tokens; }); } diff --git a/src/entrypoints/app.js b/src/entrypoints/app.js index 8f64cd4a4625..e2d20497a5b7 100644 --- a/src/entrypoints/app.js +++ b/src/entrypoints/app.js @@ -235,13 +235,20 @@ class HomeAssistant extends LocalizeMixin(PolymerElement) { const host = window.location.protocol + '//' + window.location.host; const auth = conn.options; try { + // Refresh token if it will expire in 30 seconds + if (auth.accessToken && Date.now() + 30000 > auth.expires) { + const accessToken = await window.refreshToken(); + conn.options.accessToken = accessToken.access_token; + conn.options.expires = accessToken.expires; + } return await hassCallApi(host, auth, method, path, parameters); } catch (err) { if (!err || err.status_code !== 401 || !auth.accessToken) throw err; // If we connect with access token and get 401, refresh token and try again const accessToken = await window.refreshToken(); - conn.options.accessToken = accessToken; + conn.options.accessToken = accessToken.access_token; + conn.options.expires = accessToken.expires; return await hassCallApi(host, auth, method, path, parameters); } }, diff --git a/src/entrypoints/core.js b/src/entrypoints/core.js index 76647a943086..0de0d6ce7aa9 100644 --- a/src/entrypoints/core.js +++ b/src/entrypoints/core.js @@ -18,7 +18,8 @@ const init = window.createHassConnection = function (password, accessToken) { if (password) { options.authToken = password; } else if (accessToken) { - options.accessToken = accessToken; + options.accessToken = accessToken.access_token; + options.expires = accessToken.expires; } return createConnection(url, options) .then(function (conn) { @@ -40,7 +41,10 @@ window.refreshToken = () => refreshToken_(clientId(), window.tokens.refresh_token).then((accessTokenResp) => { window.tokens.access_token = accessTokenResp.access_token; localStorage.tokens = JSON.stringify(window.tokens); - return accessTokenResp.access_token; + return { + access_token: accessTokenResp.access_token, + expires: window.tokens.expires + }; }, () => redirectLogin()); function resolveCode(code) { @@ -66,11 +70,24 @@ function main() { } if (localStorage.tokens) { window.tokens = JSON.parse(localStorage.tokens); - window.hassConnection = init(null, window.tokens.access_token).catch((err) => { - if (err !== ERR_INVALID_AUTH) throw err; + if (window.tokens.expires === undefined) { + // for those tokens got from previous version + window.tokens.expires = Date.now() - 1; + } + if (Date.now() + 30000 > window.tokens.expires) { + // refresh access token if it will expire in 30 seconds to avoid invalid auth event + window.hassConnection = window.refreshToken().then(accessToken => init(null, accessToken)); + } else { + const accessTokenObject = { + access_token: window.tokens.access_token, + expires: window.tokens.expires + }; + window.hassConnection = init(null, accessTokenObject).catch((err) => { + if (err !== ERR_INVALID_AUTH) throw err; - return window.refreshToken().then(accessToken => init(null, accessToken)); - }); + return window.refreshToken().then(accessToken => init(null, accessToken)); + }); + } return; } redirectLogin();