Commit fb62f636 by Samuel Taniel Mulyadi

add token expired

1 parent d7205995
...@@ -75,7 +75,7 @@ ...@@ -75,7 +75,7 @@
min-block-size: 100vh; /* Ensures the element covers the full viewport height */ min-block-size: 100vh; /* Ensures the element covers the full viewport height */
padding-block-start: 10px; padding-block-start: 10px;
// margin: 5% 5%;marginmarginmarginmarginmarginmarginmarginmarginmarginmarginmarginmarginmarginmarginmarginmarginmarginmarginmarginmarginmarginmarginmarginmarginmarginmarginmarginmarginmarginmarginmarginmarginmarginmarginmarginmarginmarginmarginmarginmarginmarginmarginmarginmarginmarginmarginmarginmarginmarginmarginmarginmarginmarginmarginmarginmarginmarginmarginmarginmarginmarginmarginmarginmarginmargin // margin: 5% 5%;marginmarginmarginmarginmarginmarginmarginmarginmarginmarginmarginmarginmarginmarginmarginmarginmarginmarginmarginmarginmarginmarginmarginmarginmarginmarginmarginmarginmarginmarginmarginmarginmarginmarginmarginmarginmarginmarginmarginmarginmarginmarginmarginmarginmarginmarginmarginmarginmarginmarginmarginmarginmarginmarginmarginmarginmarginmarginmarginmarginmarginmarginmarginmarginmarginmargin
} }
.main-component-margin { .main-component-margin {
......
...@@ -13,6 +13,7 @@ const username = ref<string>('') ...@@ -13,6 +13,7 @@ const username = ref<string>('')
const civitas = ref<string>('') const civitas = ref<string>('')
const kodeIdentitas = ref<string>('') const kodeIdentitas = ref<string>('')
const accessToken = ref<string>('') const accessToken = ref<string>('')
const tokenParsedExp = ref<number>(0)
const refreshTokenExp = ref<number>(0) const refreshTokenExp = ref<number>(0)
const roles = ref<string[]>([]) const roles = ref<string[]>([])
const selectedRole = useStorage('selectedRole', 'admin') const selectedRole = useStorage('selectedRole', 'admin')
...@@ -28,6 +29,7 @@ const refresh = (): void => { ...@@ -28,6 +29,7 @@ const refresh = (): void => {
username.value = tokenParsed.preferred_username || '' username.value = tokenParsed.preferred_username || ''
civitas.value = tokenParsed.civitas || '' civitas.value = tokenParsed.civitas || ''
kodeIdentitas.value = tokenParsed.kodeIdentitas || '' kodeIdentitas.value = tokenParsed.kodeIdentitas || ''
tokenParsedExp.value = tokenParsed.exp || 0
accessToken.value = keycloakInstance.token || '' accessToken.value = keycloakInstance.token || ''
refreshTokenExp.value = refreshedTokenParsed.exp || 0 refreshTokenExp.value = refreshedTokenParsed.exp || 0
roles.value = keycloakInstance.resourceAccess?.vueplayground?.roles ?? [] roles.value = keycloakInstance.resourceAccess?.vueplayground?.roles ?? []
......
<script lang="ts" setup> <script lang="ts" setup>
import { HorizontalNavLayout } from '@layouts' import { HorizontalNavLayout } from '@layouts'
import navItems from '@/navigation/horizontal' import { computed, onMounted, onUnmounted, ref } from 'vue'
import { useKeycloakStore } from '@/@core/stores/keycloakStore'
import keycloakInstance from '@/keycloak'
// Components
import Footer from '@/layouts/components/Footer.vue' import Footer from '@/layouts/components/Footer.vue'
import NavbarThemeSwitcher from '@/layouts/components/NavbarThemeSwitcher.vue' import NavbarThemeSwitcher from '@/layouts/components/NavbarThemeSwitcher.vue'
import NavbarTokenExpiredTime from '@/layouts/components/NavbarTokenExpiredTime.vue'
import UserProfile from '@/layouts/components/UserProfile.vue' import UserProfile from '@/layouts/components/UserProfile.vue'
import navItems from '@/navigation/horizontal'
// Keycloak & state
const keycloakStore = useKeycloakStore()
const authenticated = computed(() => keycloakStore.authenticated)
const now = ref(Math.floor(Date.now() / 1000))
const tokenLifetime = ref(0)
let timer: ReturnType<typeof setInterval>
onMounted(() => {
// Set tokenLifetime only once on mount
if (keycloakInstance.tokenParsed?.exp && keycloakInstance.tokenParsed?.iat)
tokenLifetime.value = keycloakInstance.tokenParsed.exp - keycloakInstance.tokenParsed.iat
// Start timer
timer = setInterval(() => {
now.value = Math.floor(Date.now() / 1000)
}, 1000)
})
onUnmounted(() => {
clearInterval(timer)
})
// Computed expiration values
const computedExpIn = computed(() => {
return authenticated.value && keycloakInstance.tokenParsed?.exp
? Math.max(keycloakInstance.tokenParsed?.exp - now.value, 0)
: 0
})
</script> </script>
<template> <template>
...@@ -39,10 +73,27 @@ import UserProfile from '@/layouts/components/UserProfile.vue' ...@@ -39,10 +73,27 @@ import UserProfile from '@/layouts/components/UserProfile.vue'
:languages="themeConfig.app.i18n.langConfig" :languages="themeConfig.app.i18n.langConfig"
/> />
--> -->
<NavbarTokenExpiredTime />
<NavbarThemeSwitcher /> <NavbarThemeSwitcher />
<!-- <NavbarShortcuts /> --> <!-- <NavbarShortcuts /> -->
<!-- <NavBarNotifications class="me-2" /> --> <!-- <NavBarNotifications class="me-2" /> -->
<!--
<div class="pa-4">
<VAlert
v-if="authenticated"
type="info"
border="start"
variant="outlined"
class="mb-4"
>
<h3 class="text-h6 font-weight-bold">
Access token expires in {{ computedExpIn }} sec,
Refresh token in {{ computedRefExpIn }} sec,
Session: {{ computedSessionTimer }}
</h3>
</VAlert>
</div>
-->
<UserProfile /> <UserProfile />
</template> </template>
......
...@@ -5,6 +5,7 @@ import navItems from '@/navigation/vertical' ...@@ -5,6 +5,7 @@ import navItems from '@/navigation/vertical'
// Components // Components
import Footer from '@/layouts/components/Footer.vue' import Footer from '@/layouts/components/Footer.vue'
import NavbarThemeSwitcher from '@/layouts/components/NavbarThemeSwitcher.vue' import NavbarThemeSwitcher from '@/layouts/components/NavbarThemeSwitcher.vue'
import NavbarTokenExpiredTime from '@/layouts/components/NavbarTokenExpiredTime.vue'
import UserProfile from '@/layouts/components/UserProfile.vue' import UserProfile from '@/layouts/components/UserProfile.vue'
// @layouts plugin // @layouts plugin
...@@ -41,6 +42,7 @@ import UserProfile from '@/layouts/components/UserProfile.vue' ...@@ -41,6 +42,7 @@ import UserProfile from '@/layouts/components/UserProfile.vue'
:languages="themeConfig.app.i18n.langConfig" :languages="themeConfig.app.i18n.langConfig"
/> />
--> -->
<NavbarTokenExpiredTime />
<NavbarThemeSwitcher /> <NavbarThemeSwitcher />
<!-- <NavbarShortcuts /> --> <!-- <NavbarShortcuts /> -->
<!-- <NavBarNotifications class="me-2" /> --> <!-- <NavBarNotifications class="me-2" /> -->
......
<script setup lang="ts">
import { computed, onMounted, onUnmounted, ref } from 'vue'
import { useKeycloakStore } from '@/@core/stores/keycloakStore'
import keycloakInstance from '@/keycloak'
const keycloakStore = useKeycloakStore()
const authenticated = computed(() => keycloakStore.authenticated)
const now = ref(Math.floor(Date.now() / 1000))
const tokenLifetime = ref(0)
let timer: ReturnType<typeof setInterval>
onMounted(() => {
// Set tokenLifetime only once
if (keycloakInstance.tokenParsed?.exp && keycloakInstance.tokenParsed?.iat)
tokenLifetime.value = keycloakInstance.tokenParsed.exp - keycloakInstance.tokenParsed.iat
timer = setInterval(() => {
now.value = Math.floor(Date.now() / 1000)
}, 1000)
})
onUnmounted(() => {
clearInterval(timer)
})
const computedExpIn = computed(() => {
return authenticated.value && keycloakInstance.tokenParsed?.exp
? Math.max(keycloakInstance.tokenParsed.exp - now.value, 0)
: 0
})
</script>
<template>
<div
v-if="authenticated"
class="me-4"
style="position: relative; block-size: 40px; inline-size: 40px;"
>
<VProgressCircular
:model-value="(computedExpIn / tokenLifetime) * 100"
:size="40"
:width="3"
color="primary"
/>
<div
class="text-subtitle-1 font-weight-bold"
style="position: absolute; inset-block-start: 50%; inset-inline-start: 50%; transform: translate(-50%, -50%);"
>
{{ computedExpIn }}
</div>
</div>
</template>
...@@ -15,6 +15,19 @@ export default defineNuxtPlugin(async nuxtApp => { ...@@ -15,6 +15,19 @@ export default defineNuxtPlugin(async nuxtApp => {
keycloakStore.refresh() keycloakStore.refresh()
console.log('User is authenticated') console.log('User is authenticated')
navigateTo('/profile') navigateTo('/profile')
setInterval(() => {
const now = Math.floor(Date.now() / 1000)
const tokenExp = keycloakInstance.tokenParsed?.exp ?? 0
if (tokenExp <= now) {
console.warn('Token expired. Logging out...')
keycloakInstance.logout({ redirectUri: `${window.location.origin}/login` })
}
else {
console.log('Token expires in:', tokenExp - now, 'seconds')
}
}, 10_000)
} }
else { else {
console.log('User is not authenticated') console.log('User is not authenticated')
......
Markdown is supported
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!