@sbc-connect/nuxt-auth 0.1.5 → 0.1.7

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.
Files changed (40) hide show
  1. package/.env.example +25 -1
  2. package/CHANGELOG.md +36 -0
  3. package/app/app.config.ts +14 -0
  4. package/app/components/Connect/Header/AccountLabel.vue +35 -0
  5. package/app/components/Connect/Header/AccountOptionsMenu.vue +52 -0
  6. package/app/components/Connect/Header/Auth.vue +14 -0
  7. package/app/components/Connect/Header/AuthenticatedOptions.vue +13 -0
  8. package/app/components/Connect/Header/CreateAccountButton.vue +13 -0
  9. package/app/components/Connect/Header/LoginMenu.vue +27 -0
  10. package/app/components/Connect/Header/Notifications.vue +30 -0
  11. package/app/components/Connect/Header/UnauthenticatedOptions.vue +15 -0
  12. package/app/components/HelloWorld/Auth.vue +2 -2
  13. package/app/composables/useConnectAuth.ts +111 -0
  14. package/app/composables/useConnectHeaderOptions.ts +233 -0
  15. package/app/enums/account-status.ts +9 -0
  16. package/app/enums/account-type.ts +6 -0
  17. package/app/enums/connect-auth-storage-keys.ts +5 -0
  18. package/app/enums/connect-error-category.ts +6 -0
  19. package/app/enums/connect-idp-hint.ts +6 -0
  20. package/app/enums/connect-login-source.ts +6 -0
  21. package/app/enums/user-settings-type.ts +5 -0
  22. package/app/interfaces/connect-account.ts +10 -0
  23. package/app/interfaces/connect-api-error.ts +6 -0
  24. package/app/interfaces/connect-auth-user.ts +10 -0
  25. package/app/interfaces/connect-user-settings.ts +10 -0
  26. package/app/layouts/ConnectAuth.vue +8 -0
  27. package/app/middleware/01.setup-accounts.global.ts +13 -0
  28. package/app/middleware/02.keycloak-params.global.ts +15 -0
  29. package/app/plugins/auth-api.ts +28 -0
  30. package/app/plugins/connect-auth.client.ts +105 -0
  31. package/app/stores/connect-account.ts +236 -0
  32. package/app/types/auth-app-config.d.ts +18 -0
  33. package/i18n/locales/en-CA.ts +31 -0
  34. package/i18n/locales/fr-CA.ts +1 -0
  35. package/modules/auth-assets/index.ts +15 -0
  36. package/modules/auth-assets/runtime/assets/connect-auth-tw.css +2 -0
  37. package/nuxt.config.ts +53 -6
  38. package/package.json +14 -10
  39. package/app/assets/css/tw-auth.css +0 -2
  40. package/app.config.ts +0 -5
@@ -0,0 +1,6 @@
1
+ export enum ConnectErrorCategory {
2
+ USER_ACCOUNTS = 'user-accounts',
3
+ ACCOUNT_LIST = 'account-list',
4
+ PENDING_APPROVAL_COUNT = 'pending-approval-count',
5
+ USER_INFO = 'user-info'
6
+ }
@@ -0,0 +1,6 @@
1
+ export enum ConnectIdpHint {
2
+ BCROS = 'bcros',
3
+ IDIR = 'idir',
4
+ BCSC = 'bcsc',
5
+ BCEID = 'bceid'
6
+ }
@@ -0,0 +1,6 @@
1
+ export enum ConnectLoginSource {
2
+ BCROS = 'BCROS',
3
+ IDIR = 'IDIR',
4
+ BCSC = 'BCSC',
5
+ BCEID = 'BCEID'
6
+ }
@@ -0,0 +1,5 @@
1
+ export enum UserSettingsType {
2
+ ACCOUNT = 'ACCOUNT',
3
+ CREATE_ACCOUNT = 'CREATE_ACCOUNT',
4
+ USER_PROFILE = 'USER_PROFILE'
5
+ }
@@ -0,0 +1,10 @@
1
+ export interface ConnectAccount {
2
+ id: number
3
+ accountType: AccountType
4
+ accountStatus: AccountStatus
5
+ additionalLabel?: string
6
+ label: string
7
+ type: UserSettingsType.ACCOUNT
8
+ urlpath: string
9
+ urlorigin: string
10
+ }
@@ -0,0 +1,6 @@
1
+ export interface ConnectApiError {
2
+ category: ConnectErrorCategory
3
+ detail?: string | string[]
4
+ message: string
5
+ statusCode: number
6
+ }
@@ -0,0 +1,10 @@
1
+ export interface ConnectAuthUser {
2
+ firstName: string
3
+ lastName: string
4
+ fullName: string
5
+ userName: string
6
+ email: string
7
+ keycloakGuid: string // sub
8
+ loginSource: ConnectLoginSource
9
+ roles: string[]
10
+ }
@@ -0,0 +1,10 @@
1
+ export interface ConnectUserSettings {
2
+ id: number
3
+ type: UserSettingsType
4
+ urlpath: string
5
+ urlorigin: string
6
+ accountType?: AccountType
7
+ accountStatus?: AccountStatus
8
+ additionalLabel?: string
9
+ label?: string
10
+ }
@@ -0,0 +1,8 @@
1
+ <template>
2
+ <ConnectLayout>
3
+ <template #header>
4
+ <ConnectHeaderAuth />
5
+ </template>
6
+ <slot />
7
+ </ConnectLayout>
8
+ </template>
@@ -0,0 +1,13 @@
1
+ export default defineNuxtRouteMiddleware(async (to) => {
2
+ if (import.meta.client) { // only run on client
3
+ const { isAuthenticated } = useConnectAuth()
4
+ if (isAuthenticated.value) {
5
+ const accountStore = useConnectAccountStore()
6
+ await accountStore.initAccountStore()
7
+
8
+ if (to.query.accountid) {
9
+ accountStore.switchCurrentAccount(parseInt(to.query.accountid as string))
10
+ }
11
+ }
12
+ }
13
+ })
@@ -0,0 +1,15 @@
1
+ export default defineNuxtRouteMiddleware((to) => {
2
+ if (import.meta.server) {
3
+ return
4
+ }
5
+ // remove query params in url added by keycloak
6
+ if (to.query) {
7
+ const params = new URLSearchParams(to.fullPath.split('?')[1])
8
+ params.delete('state')
9
+ params.delete('session_state')
10
+ params.delete('code')
11
+ params.delete('error')
12
+ params.delete('iss')
13
+ to.fullPath = to.path + (params.size > 0 ? `?${params}` : '') + to.hash
14
+ }
15
+ })
@@ -0,0 +1,28 @@
1
+ export default defineNuxtPlugin((nuxtApp) => {
2
+ const rtc = nuxtApp.$config.public
3
+ const authApiUrl = rtc.authApiUrl + rtc.authApiVersion
4
+ const appName = rtc.appName
5
+ const xApiKey = rtc.xApiKey
6
+
7
+ const api = $fetch.create({
8
+ baseURL: authApiUrl,
9
+ async onRequest({ options }) {
10
+ const auth = useConnectAuth()
11
+ const accountStore = useConnectAccountStore()
12
+
13
+ const token = await auth.getToken()
14
+ const accountId = accountStore.currentAccount.id
15
+
16
+ options.headers.set('Authorization', `Bearer ${token}`)
17
+ options.headers.set('App-Name', appName)
18
+ options.headers.set('X-Apikey', xApiKey)
19
+ options.headers.set('Account-Id', String(accountId))
20
+ }
21
+ })
22
+
23
+ return {
24
+ provide: {
25
+ authApi: api
26
+ }
27
+ }
28
+ })
@@ -0,0 +1,105 @@
1
+ import Keycloak from 'keycloak-js'
2
+
3
+ export default defineNuxtPlugin(async () => {
4
+ const rtc = useRuntimeConfig().public
5
+
6
+ // define new keycloak
7
+ const keycloak = new Keycloak({
8
+ url: rtc.idpUrl,
9
+ realm: rtc.idpRealm,
10
+ clientId: rtc.idpClientid
11
+ })
12
+
13
+ try {
14
+ // default behaviour when keycloak session expires
15
+ // try to update token - log out if token update fails
16
+ // callbacks must be registered before 'init'
17
+ // https://www.keycloak.org/securing-apps/javascript-adapter#_callback_events
18
+ keycloak.onTokenExpired = async () => {
19
+ try {
20
+ console.info('[Auth] Token expired, refreshing token...')
21
+ await keycloak.updateToken(minValidity)
22
+ console.info('[Auth] Token refreshed.')
23
+ } catch (error) {
24
+ console.error('[Auth] Failed to refresh token on expiration; logging out.', error)
25
+ keycloak.logout()
26
+ }
27
+ }
28
+
29
+ // init keycloak instance
30
+ await keycloak.init({
31
+ onLoad: 'check-sso',
32
+ responseMode: 'query',
33
+ pkceMethod: 'S256'
34
+ })
35
+ } catch (error) {
36
+ console.error('[Auth] Failed to initialize Keycloak adapter: ', error)
37
+ }
38
+
39
+ // TODO: add to env
40
+ const refreshIntervalTimeout = 30000 // rtc.tokenRefreshInterval as number
41
+ const minValidity = 120 // toValue((rtc.tokenMinValidity as number) / 1000) // convert to seconds
42
+ const idleTimeout = 1800000 // rtc.sessionIdleTimeout as number
43
+
44
+ // const route = useRoute()
45
+ const { idle } = useIdle(idleTimeout)
46
+
47
+ // executed when user is authenticated and idle = true
48
+ // TODO: manage session expiry
49
+ async function sessionExpired() {
50
+ // if (route.meta.sessionExpiredFn) { // if route meta provided, override default behaviour
51
+ // await route.meta.sessionExpiredFn()
52
+ // } else { // open expiry modal
53
+ // await useConnectModals().openSessionExpiringModal()
54
+ // }
55
+ console.info('TODO - MANAGE SESSION EXPIRY')
56
+ }
57
+
58
+ // refresh token if expiring within <minValidity> - checks every <refreshIntervalTimeout>
59
+ function scheduleRefreshToken() {
60
+ console.info('[Auth] Verifying token validity.')
61
+
62
+ setTimeout(async () => {
63
+ if (keycloak.isTokenExpired(minValidity)) {
64
+ console.info('[Auth] Token set to expire soon. Refreshing token...')
65
+ try {
66
+ await keycloak.updateToken(minValidity)
67
+ console.info('[Auth] Token refreshed.')
68
+ } catch (error) {
69
+ console.error('[Auth] Failed to refresh token; logging out.', error)
70
+ keycloak.logout() // log user out if token update fails
71
+ }
72
+ }
73
+
74
+ scheduleRefreshToken()
75
+ }, refreshIntervalTimeout)
76
+ }
77
+
78
+ // Watch for changes in authentication and idle state
79
+ // When the user is authenticated and not idle, start the refresh schedule
80
+ // Execute session expiry handling if user authenticated and inactive
81
+ watch(
82
+ [() => keycloak.authenticated, () => idle.value],
83
+ async ([isAuth, isIdle]) => {
84
+ if (isAuth) {
85
+ // TODO: add storage keys
86
+ // sessionStorage.removeItem(ConnectStorageKeys.CONNECT_SESSION_EXPIRED)
87
+ if (!isIdle) {
88
+ console.info('[Auth] Starting token refresh schedule.')
89
+ scheduleRefreshToken()
90
+ } else {
91
+ console.warn('[Auth] User session expired due to inactivity. Starting session expiry process.')
92
+ await sessionExpired()
93
+ }
94
+ }
95
+ },
96
+ { immediate: true }
97
+ )
98
+
99
+ return {
100
+ provide: {
101
+ // provide global auth instance
102
+ connectAuth: keycloak
103
+ }
104
+ }
105
+ })
@@ -0,0 +1,236 @@
1
+ export const useConnectAccountStore = defineStore('connect-auth-account-store', () => {
2
+ const { $authApi } = useNuxtApp()
3
+ const rtc = useRuntimeConfig().public
4
+ const { authUser } = useConnectAuth()
5
+ // selected user account
6
+ const currentAccount = ref<ConnectAccount>({} as ConnectAccount)
7
+ const userAccounts = ref<ConnectAccount[]>([])
8
+ const currentAccountName = computed<string>(() => currentAccount.value?.label || '')
9
+ const pendingApprovalCount = ref<number>(0)
10
+ const user = computed(() => authUser.value)
11
+ const userFirstName = ref<string>(user.value?.firstName || '-')
12
+ const userLastName = ref<string>(user.value?.lastName || '')
13
+ const userFullName = computed(() => `${userFirstName.value} ${userLastName.value}`)
14
+ const errors = ref<ConnectApiError[]>([])
15
+
16
+ /**
17
+ * Checks if the current account or the Keycloak user has any of the specified roles.
18
+ *
19
+ * @param roles - An array of roles to check against the current account or Keycloak user roles.
20
+ * @returns Returns `true` if the current account has one of the roles, or if the Keycloak user has one of the roles.
21
+ *
22
+ * @example
23
+ * // Assuming the current account has the type 'admin' and the authUser has the roles ['editor', 'viewer', 'admin']:
24
+ * const rolesToCheck = ['admin', 'superadmin'];
25
+ * const hasRequiredRole = hasRoles(rolesToCheck); // true
26
+ */
27
+ function hasRoles(roles: string[]): boolean {
28
+ const currentAccountHasRoles = roles.includes(currentAccount.value.accountType)
29
+ const authUserHasRoles = roles.some(role => authUser.value.roles.includes(role))
30
+ return currentAccountHasRoles || authUserHasRoles
31
+ }
32
+
33
+ /**
34
+ * Checks if the given account ID matches the ID of the current account in the store.
35
+ *
36
+ * @param accountId - The account ID to check.
37
+ * @returns True if the given account ID matches the current account ID, false otherwise.
38
+ */
39
+ function isCurrentAccount(accountId: number): boolean {
40
+ return accountId === currentAccount.value.id
41
+ }
42
+
43
+ /** Get user information from AUTH */
44
+ async function getAuthUserProfile(identifier: string): Promise<{ firstname: string, lastname: string } | undefined> {
45
+ try {
46
+ return $authApi<{ firstname: string, lastname: string }>(`/users/${identifier}`, {
47
+ parseResponse: JSON.parse,
48
+ onResponseError({ response }) {
49
+ errors.value.push({
50
+ statusCode: response.status || 500,
51
+ message: response._data?.message || response._data?.description || 'Error fetching user info.',
52
+ detail: response._data.detail || '',
53
+ category: ConnectErrorCategory.USER_INFO
54
+ })
55
+ }
56
+ })
57
+ } catch (e) {
58
+ console.error('Error fetching user info.', e)
59
+ // logFetchError(e, 'Error fetching user info.')
60
+ }
61
+ }
62
+
63
+ /** Update user information in AUTH with current token info */
64
+ async function updateAuthUserInfo(): Promise<void> {
65
+ try {
66
+ await $authApi('/users', {
67
+ method: 'POST',
68
+ body: { isLogin: true }
69
+ })
70
+ } catch (e) {
71
+ console.error('Error updating auth user info', e)
72
+ // logFetchError(e, 'Error updating auth user info')
73
+ }
74
+ }
75
+
76
+ /** Set user name information */
77
+ async function setUserName() {
78
+ const authUserInfo = await getAuthUserProfile('@me')
79
+ if (authUserInfo?.firstname && authUserInfo?.lastname) {
80
+ userFirstName.value = authUserInfo.firstname
81
+ userLastName.value = authUserInfo.lastname
82
+ return
83
+ }
84
+ userFirstName.value = user.value?.firstName || '-'
85
+ userLastName.value = user.value?.lastName || ''
86
+ }
87
+
88
+ /** Get the user's account list */
89
+ async function getUserAccounts(): Promise<ConnectAccount[] | undefined> {
90
+ if (!authUser.value?.keycloakGuid) {
91
+ return undefined
92
+ }
93
+ try {
94
+ // TODO: use orgs fetch instead to get branch name ? $authApi<UserSettings[]>('/users/orgs')
95
+ const response = await $authApi<ConnectUserSettings[]>(`/users/${authUser.value.keycloakGuid}/settings`, {
96
+ onResponseError({ response }) {
97
+ errors.value.push({
98
+ statusCode: response.status || 500,
99
+ message: response._data?.message || 'Error retrieving user accounts.',
100
+ detail: response._data.detail || '',
101
+ category: ConnectErrorCategory.ACCOUNT_LIST
102
+ })
103
+ }
104
+ })
105
+
106
+ return response?.filter(setting => setting.type === UserSettingsType.ACCOUNT) as ConnectAccount[]
107
+ } catch (e) {
108
+ console.error('Error retrieving user accounts', e)
109
+ // logFetchError(e, 'Error retrieving user accounts')
110
+ return undefined
111
+ }
112
+ }
113
+
114
+ /** Set the user account list and current account */
115
+ async function setAccountInfo(): Promise<void> {
116
+ const accounts = await getUserAccounts()
117
+ if (accounts && accounts[0]) {
118
+ userAccounts.value = accounts
119
+ if (!currentAccount.value.id || !userAccounts.value.some(account => account.id === currentAccount.value.id)) {
120
+ currentAccount.value = accounts[0]
121
+ }
122
+ }
123
+ }
124
+
125
+ /** Switch the current account to the given account ID if it exists in the user's account list */
126
+ function switchCurrentAccount(accountId: number) {
127
+ const account = userAccounts.value.find(account => account.id === accountId)
128
+ if (account) {
129
+ currentAccount.value = account
130
+ }
131
+ }
132
+
133
+ async function getPendingApprovalCount(): Promise<void> {
134
+ const accountId = currentAccount.value?.id
135
+ const keycloakGuid = authUser.value?.keycloakGuid
136
+ if (!accountId || !keycloakGuid) {
137
+ return
138
+ }
139
+ try {
140
+ const response = await $authApi<{ count: number }>(`/users/${keycloakGuid}/org/${accountId}/notifications`, {
141
+ onResponseError({ response }) {
142
+ errors.value.push({
143
+ statusCode: response.status || 500,
144
+ message: response._data.message || 'Error retrieving pending approvals.',
145
+ detail: response._data.detail || '',
146
+ category: ConnectErrorCategory.PENDING_APPROVAL_COUNT
147
+ })
148
+ }
149
+ })
150
+
151
+ pendingApprovalCount.value = response?.count || 0
152
+ } catch (e) {
153
+ console.error('Error retrieving pending approvals', e)
154
+ // logFetchError(e, 'Error retrieving pending approvals')
155
+ }
156
+ }
157
+
158
+ async function checkAccountStatus() {
159
+ // redirect if account status is suspended or in review
160
+ if ([AccountStatus.NSF_SUSPENDED, AccountStatus.SUSPENDED].includes(currentAccount.value?.accountStatus)) {
161
+ // Avoid redirecting when navigating back from PAYBC for NSF or signout.
162
+ const endPath = useRoute().path.split('/').pop() as string
163
+ const isAllowedPath = ['return-cc-payment', 'signout'].includes(endPath)
164
+ if (!isAllowedPath) {
165
+ // URL not allowed so redirect
166
+ const redirectUrl = `${rtc.authWebURL}/account-freeze`
167
+ // TODO: should probably change this to check 'appName' when auth starts using the core layer
168
+ const external = rtc.authWebURL !== rtc.baseUrl
169
+ await navigateTo(redirectUrl, { external })
170
+ }
171
+ } else if (currentAccount.value?.accountStatus === AccountStatus.PENDING_STAFF_REVIEW) {
172
+ // check the path is allowed for pending approval account
173
+ const endPath = useRoute().path.split('/').pop() as string
174
+ const isAllowedPath = ['setup-non-bcsc-account', 'signout'].includes(endPath)
175
+ if (!isAllowedPath) {
176
+ // URL not allowed so redirect
177
+ // TODO: auth web pending approval page is not displaying the encoded name correctly.
178
+ // It would be better if we could pass the account id here and then the pending page could infer the name.
179
+ // const accountNameEncoded = encodeURIComponent(btoa(currentAccount.value?.id))
180
+ // Temporary: remove spaces and it shows something legible at least
181
+ const accountNameEncoded = currentAccount.value?.label?.replaceAll(' ', '')
182
+ const redirectUrl = `${rtc.authWebURL}/pendingapproval/${accountNameEncoded}/true`
183
+ // TODO: should probably change this to check 'appName' when auth starts using the core layer
184
+ const external = rtc.authWebURL !== rtc.baseUrl
185
+ await navigateTo(redirectUrl, { external })
186
+ }
187
+ }
188
+ }
189
+
190
+ async function initAccountStore(): Promise<void> {
191
+ await Promise.all([
192
+ setAccountInfo(),
193
+ updateAuthUserInfo(),
194
+ setUserName()
195
+ ])
196
+
197
+ if (currentAccount.value.id) {
198
+ await Promise.all([
199
+ checkAccountStatus(),
200
+ getPendingApprovalCount()
201
+ ])
202
+ }
203
+ }
204
+
205
+ function $reset() {
206
+ sessionStorage.removeItem('connect-auth-account-store')
207
+ currentAccount.value = {} as ConnectAccount
208
+ userAccounts.value = []
209
+ pendingApprovalCount.value = 0
210
+ errors.value = []
211
+ userFirstName.value = user.value?.firstName || '-'
212
+ userLastName.value = user.value?.lastName || ''
213
+ }
214
+
215
+ return {
216
+ currentAccount,
217
+ currentAccountName,
218
+ userAccounts,
219
+ pendingApprovalCount,
220
+ errors,
221
+ userFullName,
222
+ checkAccountStatus,
223
+ setUserName,
224
+ hasRoles,
225
+ isCurrentAccount,
226
+ getAuthUserProfile,
227
+ setAccountInfo,
228
+ getUserAccounts,
229
+ switchCurrentAccount,
230
+ getPendingApprovalCount,
231
+ initAccountStore,
232
+ $reset
233
+ }
234
+ },
235
+ { persist: true } // persist in session storage
236
+ )
@@ -0,0 +1,18 @@
1
+ declare module '@nuxt/schema' {
2
+ interface AppConfigInput {
3
+ connect?: {
4
+ login?: {
5
+ redirectPath?: string
6
+ idps?: Array<'bcsc' | 'bceid' | 'idir'>
7
+ }
8
+ header?: {
9
+ loginMenu?: boolean
10
+ createAccount?: boolean
11
+ notifications?: boolean
12
+ accountOptionsMenu?: boolean
13
+ }
14
+ }
15
+ }
16
+ }
17
+
18
+ export {}
@@ -0,0 +1,31 @@
1
+ /* eslint-disable max-len */
2
+ export default {
3
+ /* Ordering should be alphabetical unless otherwise specified */
4
+ connect: {
5
+ label: {
6
+ accountInfo: 'Account Info',
7
+ accountOptionsMenu: 'Account Options Menu',
8
+ accountSettings: 'Account Settings',
9
+ bceid: 'BCeID',
10
+ bcsc: 'BC Services Card',
11
+ createAccount: 'Create Account',
12
+ editProfile: 'Edit Profile',
13
+ idir: 'IDIR',
14
+ logout: 'Log out',
15
+ login: 'Log in',
16
+ mainMenu: 'Main Menu',
17
+ notifications: 'Notifications',
18
+ notificationsAria: 'Notifications, {count} unread',
19
+ selectLoginMethod: 'Select log in method',
20
+ switchAccount: 'Switch Account',
21
+ teamMembers: 'Team Members',
22
+ transactions: 'Transactions'
23
+ },
24
+ text: {
25
+ notifications: {
26
+ none: 'No Notifications',
27
+ teamMemberApproval: '{count} team member requires approval to access this account. | {count} team members require approval to access this account.'
28
+ }
29
+ }
30
+ }
31
+ }
@@ -0,0 +1 @@
1
+ export default {}
@@ -0,0 +1,15 @@
1
+ import { defineNuxtModule, createResolver } from 'nuxt/kit'
2
+
3
+ export default defineNuxtModule({
4
+ meta: {
5
+ name: 'auth-assets',
6
+ configKey: 'authAssets'
7
+ },
8
+ defaults: {},
9
+ async setup(_options, _nuxt) {
10
+ console.info('Setting up **auth** assets module')
11
+ const resolver = createResolver(import.meta.url)
12
+
13
+ _nuxt.options.css.push(resolver.resolve('./runtime/assets/connect-auth-tw.css'))
14
+ }
15
+ })
@@ -0,0 +1,2 @@
1
+ @import "#connect-theme";
2
+ @source "../../../../app";
package/nuxt.config.ts CHANGED
@@ -12,19 +12,66 @@ export default defineNuxtConfig({
12
12
 
13
13
  extends: ['@sbc-connect/nuxt-base'],
14
14
 
15
+ imports: {
16
+ dirs: ['interfaces', 'types', 'enums', 'stores']
17
+ },
18
+
19
+ modules: [
20
+ '@pinia/nuxt',
21
+ 'pinia-plugin-persistedstate/nuxt'
22
+ ],
23
+
15
24
  alias: {
16
25
  '#auth': resolve('./')
17
26
  },
18
27
 
19
- css: [
20
- resolve('./app/assets/css/tw-auth.css')
21
- ],
28
+ icon: {
29
+ clientBundle: {
30
+ icons: [
31
+ 'mdi:bell-outline',
32
+ 'mdi:account-outline',
33
+ 'mdi:logout-variant',
34
+ 'mdi:account-group-outline',
35
+ 'mdi:account-card-details-outline',
36
+ 'mdi:two-factor-authentication',
37
+ 'mdi:new-box'
38
+ ]
39
+ }
40
+ },
41
+
42
+ piniaPluginPersistedstate: {
43
+ storage: 'sessionStorage'
44
+ },
45
+
46
+ i18n: {
47
+ locales: [
48
+ {
49
+ name: 'English',
50
+ code: 'en-CA',
51
+ language: 'en-CA',
52
+ dir: 'ltr',
53
+ file: 'en-CA.ts'
54
+ },
55
+ {
56
+ name: 'Français',
57
+ code: 'fr-CA',
58
+ language: 'fr-CA',
59
+ dir: 'ltr',
60
+ file: 'fr-CA.ts'
61
+ }
62
+ ]
63
+ },
22
64
 
23
65
  runtimeConfig: {
24
66
  public: {
25
- // Should in alphabetical order
26
- appName: process.env.npm_package_name || '',
27
- version: `Connect Auth Layer v${process.env.npm_package_version || ''}`
67
+ idpUrl: '',
68
+ idpRealm: '',
69
+ idpClientid: '',
70
+ siteminderLogoutUrl: '',
71
+ authApiUrl: '',
72
+ authApiVersion: '',
73
+ xApiKey: '',
74
+ authWebUrl: ''
28
75
  }
29
76
  }
30
77
  })
package/package.json CHANGED
@@ -1,30 +1,34 @@
1
1
  {
2
2
  "name": "@sbc-connect/nuxt-auth",
3
3
  "type": "module",
4
- "version": "0.1.5",
4
+ "version": "0.1.7",
5
5
  "repository": "github:bcgov/connect-nuxt",
6
6
  "license": "BSD-3-Clause",
7
7
  "main": "./nuxt.config.ts",
8
8
  "devDependencies": {
9
9
  "@axe-core/playwright": "^4.10.2",
10
10
  "@vitest/coverage-v8": "^3.2.4",
11
- "dotenv": "^17.2.0",
12
- "nuxt": "^4.0.0",
11
+ "dotenv": "^17.2.1",
12
+ "nuxt": "^4.0.2",
13
13
  "typescript": "^5.8.3",
14
- "vue-tsc": "^3.0.3",
15
- "@sbc-connect/eslint-config": "0.0.5",
16
- "@sbc-connect/playwright-config": "0.0.4",
17
- "@sbc-connect/vitest-config": "0.0.5"
14
+ "vue-tsc": "^3.0.4",
15
+ "@sbc-connect/eslint-config": "0.0.6",
16
+ "@sbc-connect/playwright-config": "0.0.5",
17
+ "@sbc-connect/vitest-config": "0.0.6"
18
18
  },
19
19
  "dependencies": {
20
- "@sbc-connect/nuxt-base": "0.1.5"
20
+ "@pinia/nuxt": "^0.11.2",
21
+ "keycloak-js": "^26.2.0",
22
+ "pinia": "^3.0.3",
23
+ "pinia-plugin-persistedstate": "^4.4.1",
24
+ "@sbc-connect/nuxt-base": "0.1.7"
21
25
  },
22
26
  "scripts": {
23
27
  "preinstall": "npx only-allow pnpm",
24
- "dev": "nuxi dev .playground",
28
+ "dev": "nuxi dev .playground --dotenv ../.env",
25
29
  "build": "nuxt build .playground",
26
30
  "build:test": "pnpm generate && npx serve .playground/.output/public",
27
- "generate": "nuxt generate .playground",
31
+ "generate": "nuxt generate .playground --dotenv ../.env",
28
32
  "preview": "nuxt preview .playground",
29
33
  "lint": "eslint .",
30
34
  "lint:fix": "eslint --fix .",