Refresh token after idle period/background tab (#7177)

Fixes #3940
This commit is contained in:
Rijk van Zanten
2021-08-04 02:36:48 +02:00
committed by GitHub
parent e8bb89e05d
commit 177f6a3275
3 changed files with 97 additions and 1 deletions

View File

@@ -22,10 +22,11 @@
<script lang="ts">
import { useI18n } from 'vue-i18n';
import { defineComponent, toRefs, watch, computed, provide } from 'vue';
import { defineComponent, toRefs, watch, computed, provide, onMounted, onUnmounted } from 'vue';
import * as stores from '@/stores';
import api, { addTokenToURL } from '@/api';
import axios from 'axios';
import { startIdleTracking, stopIdleTracking, idleTracker } from './idle';
import useWindowSize from '@/composables/use-window-size';
import setFavicon from '@/utils/set-favicon';
@@ -48,6 +49,9 @@ export default defineComponent({
};
});
onMounted(() => startIdleTracking());
onUnmounted(() => stopIdleTracking());
watch([() => serverStore.info?.project?.project_color, () => serverStore.info?.project?.project_logo], () => {
const hasCustomLogo = !!serverStore.info?.project?.project_logo;
setFavicon(serverStore.info?.project?.project_color || '#00C897', hasCustomLogo);

View File

@@ -3,6 +3,7 @@ import { dehydrate, hydrate } from '@/hydrate';
import { router } from '@/router';
import { useAppStore } from '@/stores';
import { RouteLocationRaw } from 'vue-router';
import { idleTracker } from './idle';
export type LoginCredentials = {
email: string;
@@ -37,11 +38,41 @@ export async function login(credentials: LoginCredentials): Promise<void> {
}
let refreshTimeout: any;
let idle = false;
// Prevent the auto-refresh when the app isn't in use
idleTracker.on('idle', () => {
clearTimeout(refreshTimeout);
idle = true;
});
idleTracker.on('hide', () => {
clearTimeout(refreshTimeout);
idle = true;
});
// Restart the autorefresh process when the app is used (again)
idleTracker.on('active', () => {
if (idle === true) {
refresh();
idle = false;
}
});
idleTracker.on('show', () => {
if (idle === true) {
refresh();
idle = false;
}
});
export async function refresh({ navigate }: LogoutOptions = { navigate: true }): Promise<string | undefined> {
const appStore = useAppStore();
try {
// Delete the token header if it still exists
delete api.defaults.headers.Authorization;
const response = await api.post('/auth/refresh');
const accessToken = response.data.data.access_token;

61
app/src/idle.ts Normal file
View File

@@ -0,0 +1,61 @@
import mitt from 'mitt';
const events = ['pointermove', 'pointerdown', 'keydown'];
const time = 5 * 60 * 1000; // 5 min in ms
let timeout: NodeJS.Timeout;
let visible = true;
let idle = false;
export const idleTracker = mitt();
export function startIdleTracking() {
document.addEventListener('visibilitychange', onVisibilityChange);
for (const event of events) {
document.addEventListener(event, onIdleEvents);
}
resetTimeout();
}
export function stopIdleTracking() {
document.removeEventListener('visibilitychange', onVisibilityChange);
for (const event of events) {
document.removeEventListener(event, onIdleEvents);
}
}
function onIdleEvents() {
if (idle === true) {
idle = false;
idleTracker.emit('active');
}
resetTimeout();
}
function onVisibilityChange() {
if (document.visibilityState === 'hidden' && visible === true) {
visible = false;
idleTracker.emit('hide');
}
if (document.visibilityState === 'visible' && visible === false) {
visible = true;
idleTracker.emit('show');
}
}
function resetTimeout() {
if (timeout) {
clearTimeout(timeout);
}
timeout = setTimeout(() => {
idle = true;
idleTracker.emit('idle');
}, time);
}