@sbc-connect/nuxt-auth 0.7.1 → 0.8.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -1,5 +1,23 @@
1
1
  # @sbc-connect/nuxt-auth
2
2
 
3
+ ## 0.8.1
4
+
5
+ ### Patch Changes
6
+
7
+ - Updated dependencies [[`3b9fddb`](https://github.com/bcgov/connect-nuxt/commit/3b9fddb1c634fa48c8f4426954cbb2a043f78ff1)]:
8
+ - @sbc-connect/nuxt-forms@0.7.0
9
+
10
+ ## 0.8.0
11
+
12
+ ### Minor Changes
13
+
14
+ - [#140](https://github.com/bcgov/connect-nuxt/pull/140) [`7704fda`](https://github.com/bcgov/connect-nuxt/commit/7704fda8e016b67d0928964652e94f0bb792ff6c) Thanks [@cameron-eyds](https://github.com/cameron-eyds)! - Param preservation in expiry logout and header login
15
+
16
+ ### Patch Changes
17
+
18
+ - Updated dependencies [[`83c5627`](https://github.com/bcgov/connect-nuxt/commit/83c5627689a50d6fa27f12f2ab7b2ef65e752d0e)]:
19
+ - @sbc-connect/nuxt-forms@0.6.2
20
+
3
21
  ## 0.7.1
4
22
 
5
23
  ### Patch Changes
@@ -4,11 +4,25 @@ const rtc = useRuntimeConfig().public
4
4
  const modalTimeout = rtc.sessionModalTimeout ? Number(rtc.sessionModalTimeout) : 120000
5
5
  const { t } = useI18n()
6
6
  const route = useRoute()
7
+ const localePath = useLocalePath()
7
8
 
8
9
  const emit = defineEmits<{ close: [] }>()
9
10
 
10
11
  const timeRemaining = ref(toValue((modalTimeout) / 1000))
11
12
 
13
+ // Capture the user's current location when the modal opens, before any potential URL changes
14
+ const capturedUrl = `${window.location.origin}${route.fullPath}`
15
+
16
+ /** Build a login page URL with a return param preserving the user's current location.
17
+ * The return value is double-encoded so it survives the Keycloak redirect decode
18
+ * without the original query params bleeding into the login page's query string.
19
+ */
20
+ function getSessionExpiredRedirect(): string {
21
+ const loginPath = localePath('/auth/login')
22
+ const returnUrl = encodeURIComponent(encodeURIComponent(capturedUrl))
23
+ return `${window.location.origin}${loginPath}?return=${returnUrl}`
24
+ }
25
+
12
26
  const intervalId = setInterval(async () => {
13
27
  const value = timeRemaining.value - 1
14
28
  timeRemaining.value = value < 0 ? 0 : value
@@ -18,7 +32,7 @@ const intervalId = setInterval(async () => {
18
32
  await route.meta.onBeforeSessionExpired()
19
33
  }
20
34
  sessionStorage.setItem(ConnectAuthStorageKey.CONNECT_SESSION_EXPIRED, 'true')
21
- await useConnectAuth().logout()
35
+ await useConnectAuth().logout(getSessionExpiredRedirect())
22
36
  }
23
37
  }, 1000)
24
38
 
@@ -6,7 +6,9 @@ export const useConnectAccountFlowRedirect = () => {
6
6
  const { currentAccount, userAccounts } = useConnectAccountStore()
7
7
  const localePath = useLocalePath()
8
8
  const ac = useAppConfig().connect.login
9
- const externalRedirectUrl = route.query.return as string | undefined
9
+ const externalRedirectUrl = route.query.return
10
+ ? decodeURIComponent(route.query.return as string)
11
+ : undefined
10
12
  const internalRedirectUrl = ac.redirect
11
13
  const query = { ...route.query }
12
14
  query.accountid = String(currentAccount.id)
@@ -30,9 +30,7 @@ export const useConnectAuth = () => {
30
30
 
31
31
  if (siteminderUrl) {
32
32
  const cleanedUri = redirectUri.replace(/(https?:\/\/)|(\/)+/g, '$1$2')
33
- const queryString = window.location.search
34
- const returlValue = queryString ? `${cleanedUri}${queryString}` : cleanedUri
35
- redirectUri = `${siteminderUrl}?returl=${returlValue}&retnow=1`
33
+ redirectUri = `${siteminderUrl}?returl=${encodeURIComponent(cleanedUri)}&retnow=1`
36
34
  }
37
35
 
38
36
  resetPiniaStores()
@@ -10,7 +10,7 @@ export function useConnectHeaderOptions() {
10
10
  const ac = useAppConfig().connect
11
11
  const route = useRoute()
12
12
  const overlay = useOverlay()
13
- const { t, locale: { value: locale } } = useNuxtApp().$i18n
13
+ const { t } = useNuxtApp().$i18n
14
14
  const { login, isAuthenticated, authUser } = useConnectAuth()
15
15
  const accountStore = useConnectAccountStore()
16
16
  const localePath = useLocalePath()
@@ -135,9 +135,13 @@ export function useConnectHeaderOptions() {
135
135
  return options
136
136
  })
137
137
 
138
- const loginRedirectUrl = ac.login.redirect
139
- ? appBaseUrl + locale + ac.login.redirect
140
- : undefined
138
+ // Build a redirect URL through the login page so the connect-auth middleware
139
+ // processes query params (e.g. 'return') after Keycloak authentication
140
+ function getLoginRedirectUrl(): string {
141
+ const loginPath = localePath('/auth/login')
142
+ const queryString = window.location.search
143
+ return `${appBaseUrl}${loginPath.startsWith('/') ? loginPath.slice(1) : loginPath}${queryString}`
144
+ }
141
145
 
142
146
  const loginOptionsMap: Record<'bcsc' | 'bceid' | 'idir',
143
147
  { label: string, icon: string, onSelect: () => Promise<void> }
@@ -145,17 +149,17 @@ export function useConnectHeaderOptions() {
145
149
  bcsc: {
146
150
  label: t('connect.label.bcsc'),
147
151
  icon: 'i-mdi-account-card-details-outline',
148
- onSelect: () => login(ConnectIdpHint.BCSC, loginRedirectUrl)
152
+ onSelect: () => login(ConnectIdpHint.BCSC, getLoginRedirectUrl())
149
153
  },
150
154
  bceid: {
151
155
  label: t('connect.label.bceid'),
152
156
  icon: 'i-mdi-two-factor-authentication',
153
- onSelect: () => login(ConnectIdpHint.BCEID, loginRedirectUrl)
157
+ onSelect: () => login(ConnectIdpHint.BCEID, getLoginRedirectUrl())
154
158
  },
155
159
  idir: {
156
160
  label: t('connect.label.idir'),
157
161
  icon: 'i-mdi-account-group-outline',
158
- onSelect: () => login(ConnectIdpHint.IDIR, loginRedirectUrl)
162
+ onSelect: () => login(ConnectIdpHint.IDIR, getLoginRedirectUrl())
159
163
  }
160
164
  }
161
165
 
@@ -15,6 +15,19 @@ export default defineNuxtPlugin(async () => {
15
15
  const tokenMinValidity = rtc.tokenMinValidity ? Number(rtc.tokenMinValidity) / 1000 : 120
16
16
  const sessionInactivityTimeout = rtc.sessionInactivityTimeout ? Number(rtc.sessionInactivityTimeout) : 1800000
17
17
 
18
+ // Logout via Keycloak, redirecting to the login page with a return param preserving the user's current URL.
19
+ // The return value is double-encoded so it survives the Keycloak redirect decode
20
+ // without the original query params bleeding into the login page's query string.
21
+ function logoutWithReturn(kc: Keycloak) {
22
+ const localePath = useLocalePath()
23
+ const route = useRoute()
24
+ const loginPath = localePath('/auth/login')
25
+ const currentUrl = `${window.location.origin}${route.fullPath}`
26
+ const returnUrl = encodeURIComponent(encodeURIComponent(currentUrl))
27
+ const redirectUri = `${window.location.origin}${loginPath}?return=${returnUrl}`
28
+ kc.logout({ redirectUri })
29
+ }
30
+
18
31
  try {
19
32
  // default behaviour when keycloak session expires
20
33
  // try to update token - log out if token update fails
@@ -27,7 +40,7 @@ export default defineNuxtPlugin(async () => {
27
40
  console.info('[Auth] Token refreshed.')
28
41
  } catch (error) {
29
42
  console.error('[Auth] Failed to refresh token on expiration; logging out.', error)
30
- keycloak.logout()
43
+ logoutWithReturn(keycloak)
31
44
  }
32
45
  }
33
46
 
@@ -62,7 +75,7 @@ export default defineNuxtPlugin(async () => {
62
75
  console.info('[Auth] Token refreshed.')
63
76
  } catch (error) {
64
77
  console.error('[Auth] Failed to refresh token; logging out.', error)
65
- keycloak.logout() // log user out if token update fails
78
+ logoutWithReturn(keycloak)
66
79
  }
67
80
  }
68
81
 
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@sbc-connect/nuxt-auth",
3
3
  "type": "module",
4
- "version": "0.7.1",
4
+ "version": "0.8.1",
5
5
  "repository": "github:bcgov/connect-nuxt",
6
6
  "license": "BSD-3-Clause",
7
7
  "main": "./nuxt.config.ts",
@@ -23,7 +23,7 @@
23
23
  "pinia": "3.0.4",
24
24
  "pinia-plugin-persistedstate": "4.7.1",
25
25
  "@sbc-connect/nuxt-base": "0.7.1",
26
- "@sbc-connect/nuxt-forms": "0.6.1"
26
+ "@sbc-connect/nuxt-forms": "0.7.0"
27
27
  },
28
28
  "scripts": {
29
29
  "preinstall": "npx only-allow pnpm",