@spidy092/auth-client 1.0.12 → 1.0.13

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 (4) hide show
  1. package/core.js +86 -52
  2. package/index.js +5 -2
  3. package/package.json +1 -1
  4. package/token.js +70 -0
package/core.js CHANGED
@@ -2,56 +2,9 @@
2
2
  import { setToken, clearToken, getToken } from './token';
3
3
  import { getConfig, isRouterMode } from './config';
4
4
 
5
- // ✅ Track if callback was already processed
5
+ // ✅ Track callback state with listeners
6
6
  let callbackProcessed = false;
7
7
 
8
- export function handleCallback() {
9
- const params = new URLSearchParams(window.location.search);
10
- const accessToken = params.get('access_token');
11
- const error = params.get('error');
12
-
13
- console.log('🔄 Handling authentication callback:', {
14
- mode: isRouterMode() ? 'ROUTER' : 'CLIENT',
15
- hasAccessToken: !!accessToken,
16
- error,
17
- alreadyProcessed: callbackProcessed // ✅ Log if already processed
18
- });
19
-
20
- // ✅ If already processed and we have a token, return it
21
- if (callbackProcessed) {
22
- const existingToken = getToken();
23
- if (existingToken) {
24
- console.log('🔄 Callback already processed, returning existing token');
25
- return existingToken;
26
- }
27
- }
28
-
29
- // ✅ Mark as processed first
30
- callbackProcessed = true;
31
-
32
- // Clean up session storage (only once)
33
- sessionStorage.removeItem('originalApp');
34
- sessionStorage.removeItem('returnUrl');
35
-
36
- if (error) {
37
- throw new Error(`Authentication failed: ${error}`);
38
- }
39
-
40
- if (accessToken) {
41
- setToken(accessToken);
42
- console.log('✅ Token set successfully');
43
- return accessToken;
44
- }
45
-
46
- throw new Error('No access token found in callback URL');
47
- }
48
-
49
- // ✅ Reset callback state when needed
50
- export function resetCallbackState() {
51
- callbackProcessed = false;
52
- }
53
-
54
- // Your other functions remain the same...
55
8
  export function login(clientKeyArg, redirectUriArg) {
56
9
  // ✅ Reset callback state when starting new login
57
10
  resetCallbackState();
@@ -80,10 +33,12 @@ export function login(clientKeyArg, redirectUriArg) {
80
33
  sessionStorage.setItem('originalApp', clientKey);
81
34
  sessionStorage.setItem('returnUrl', redirectUri);
82
35
 
83
- // Smart Router Logic (from my previous response)
36
+ // Smart Router Logic
84
37
  if (isRouterMode()) {
38
+ // Router mode: Direct backend authentication
85
39
  return routerLogin(clientKey, redirectUri);
86
40
  } else {
41
+ // Client mode: Redirect to centralized login
87
42
  return clientLogin(clientKey, redirectUri);
88
43
  }
89
44
  }
@@ -129,7 +84,7 @@ export function logout() {
129
84
  hasToken: !!token
130
85
  });
131
86
 
132
- // Clear local storage immediately
87
+ // Clear local storage immediately (this will trigger listeners)
133
88
  clearToken();
134
89
  sessionStorage.clear();
135
90
 
@@ -140,7 +95,7 @@ export function logout() {
140
95
  }
141
96
  }
142
97
 
143
- // Router logout (same as before)
98
+ // Router logout
144
99
  async function routerLogout(clientKey, authBaseUrl, accountUiUrl, token) {
145
100
  console.log('🏭 Router Logout: Backend logout for all sessions');
146
101
 
@@ -170,13 +125,92 @@ async function routerLogout(clientKey, authBaseUrl, accountUiUrl, token) {
170
125
  window.location.href = '/login';
171
126
  }
172
127
 
173
- // Client logout (same as before)
128
+ // Client logout
174
129
  function clientLogout(clientKey, accountUiUrl) {
175
130
  console.log('🔄 Client Logout: Redirecting to centralized login');
176
131
  const logoutUrl = `${accountUiUrl}/login?client=${clientKey}&logout=true`;
177
132
  window.location.href = logoutUrl;
178
133
  }
179
134
 
135
+ export function handleCallback() {
136
+ const params = new URLSearchParams(window.location.search);
137
+ const accessToken = params.get('access_token');
138
+ const error = params.get('error');
139
+
140
+ console.log('🔄 Handling authentication callback:', {
141
+ mode: isRouterMode() ? 'ROUTER' : 'CLIENT',
142
+ hasAccessToken: !!accessToken,
143
+ error,
144
+ alreadyProcessed: callbackProcessed
145
+ });
146
+
147
+ // ✅ If already processed and we have a token, return it
148
+ if (callbackProcessed) {
149
+ const existingToken = getToken();
150
+ if (existingToken) {
151
+ console.log('🔄 Callback already processed, returning existing token');
152
+ return existingToken;
153
+ }
154
+ }
155
+
156
+ // ✅ Mark as processed first
157
+ callbackProcessed = true;
158
+
159
+ // Clean up session storage (only once)
160
+ sessionStorage.removeItem('originalApp');
161
+ sessionStorage.removeItem('returnUrl');
162
+
163
+ if (error) {
164
+ throw new Error(`Authentication failed: ${error}`);
165
+ }
166
+
167
+ if (accessToken) {
168
+ // ✅ This will trigger token listeners
169
+ setToken(accessToken);
170
+ console.log('✅ Token set successfully, listeners notified');
171
+ return accessToken;
172
+ }
173
+
174
+ throw new Error('No access token found in callback URL');
175
+ }
176
+
177
+ // ✅ Reset callback state
178
+ export function resetCallbackState() {
179
+ callbackProcessed = false;
180
+ console.log('🔄 Callback state reset');
181
+ }
182
+
183
+ export async function refreshToken() {
184
+ const { clientKey, authBaseUrl } = getConfig();
185
+
186
+ console.log('🔄 Refreshing token:', {
187
+ clientKey,
188
+ mode: isRouterMode() ? 'ROUTER' : 'CLIENT'
189
+ });
190
+
191
+ try {
192
+ const response = await fetch(`${authBaseUrl}/refresh/${clientKey}`, {
193
+ method: 'POST',
194
+ credentials: 'include',
195
+ });
196
+
197
+ if (!response.ok) {
198
+ throw new Error('Refresh failed');
199
+ }
200
+
201
+ const { access_token } = await response.json();
202
+ // ✅ This will trigger token listeners
203
+ setToken(access_token);
204
+ console.log('✅ Token refresh successful, listeners notified');
205
+ return access_token;
206
+ } catch (err) {
207
+ // ✅ This will trigger token listeners
208
+ clearToken();
209
+ throw err;
210
+ }
211
+ }
212
+
213
+
180
214
 
181
215
  export async function refreshToken() {
182
216
  const { clientKey, authBaseUrl } = getConfig();
package/index.js CHANGED
@@ -1,7 +1,7 @@
1
1
  // auth-client/index.js
2
2
  import { setConfig, getConfig, isRouterMode } from './config';
3
3
  import { login, logout, handleCallback, refreshToken, resetCallbackState } from './core';
4
- import { getToken, setToken, clearToken } from './token';
4
+ import { getToken, setToken, clearToken, addTokenListener, removeTokenListener, getListenerCount } from './token';
5
5
  import api from './api';
6
6
  import { decodeToken, isTokenExpired } from './utils/jwt';
7
7
 
@@ -16,12 +16,15 @@ export const auth = {
16
16
  logout,
17
17
  handleCallback,
18
18
  refreshToken,
19
- resetCallbackState, // ✅ Export reset function
19
+ resetCallbackState,
20
20
 
21
21
  // 🔑 Token management
22
22
  getToken,
23
23
  setToken,
24
24
  clearToken,
25
+ addTokenListener, // ✅ Export new functions
26
+ removeTokenListener,
27
+ getListenerCount, // ✅ Debug function
25
28
 
26
29
  // 🌐 Authenticated API client
27
30
  api,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@spidy092/auth-client",
3
- "version": "1.0.12",
3
+ "version": "1.0.13",
4
4
  "description": "Scalable frontend auth SDK for centralized login using Keycloak + Auth Service.",
5
5
  "main": "index.js",
6
6
  "module": "index.js",
package/token.js CHANGED
@@ -1,12 +1,33 @@
1
+ // auth-client/token.js
1
2
  let memoryToken = null;
3
+ const listeners = new Set(); // ✅ Add listeners
2
4
 
3
5
  export function setToken(token) {
6
+ const previousToken = memoryToken;
4
7
  memoryToken = token;
8
+
5
9
  try {
6
10
  localStorage.setItem('authToken', token);
7
11
  } catch (err) {
8
12
  console.warn('Could not write token to localStorage:', err);
9
13
  }
14
+
15
+ // ✅ Notify listeners when token changes
16
+ if (previousToken !== token) {
17
+ console.log('🔔 Token changed, notifying listeners:', {
18
+ listenerCount: listeners.size,
19
+ hadToken: !!previousToken,
20
+ hasToken: !!token
21
+ });
22
+
23
+ listeners.forEach(listener => {
24
+ try {
25
+ listener(token, previousToken);
26
+ } catch (err) {
27
+ console.warn('Token listener error:', err);
28
+ }
29
+ });
30
+ }
10
31
  }
11
32
 
12
33
  export function getToken() {
@@ -22,10 +43,59 @@ export function getToken() {
22
43
  }
23
44
 
24
45
  export function clearToken() {
46
+ const previousToken = memoryToken;
25
47
  memoryToken = null;
48
+
26
49
  try {
27
50
  localStorage.removeItem('authToken');
28
51
  } catch (err) {
29
52
  console.warn('Could not clear token from localStorage:', err);
30
53
  }
54
+
55
+ // ✅ Notify listeners when token is cleared
56
+ if (previousToken) {
57
+ console.log('🔔 Token cleared, notifying listeners:', {
58
+ listenerCount: listeners.size
59
+ });
60
+
61
+ listeners.forEach(listener => {
62
+ try {
63
+ listener(null, previousToken);
64
+ } catch (err) {
65
+ console.warn('Token listener error:', err);
66
+ }
67
+ });
68
+ }
69
+ }
70
+
71
+ // ✅ Add listener management
72
+ export function addTokenListener(listener) {
73
+ if (typeof listener !== 'function') {
74
+ throw new Error('Token listener must be a function');
75
+ }
76
+
77
+ listeners.add(listener);
78
+ console.log('📎 Token listener added, total listeners:', listeners.size);
79
+
80
+ // Return cleanup function
81
+ return () => {
82
+ const removed = listeners.delete(listener);
83
+ if (removed) {
84
+ console.log('📎 Token listener removed, remaining listeners:', listeners.size);
85
+ }
86
+ return removed;
87
+ };
88
+ }
89
+
90
+ export function removeTokenListener(listener) {
91
+ const removed = listeners.delete(listener);
92
+ if (removed) {
93
+ console.log('📎 Token listener removed, remaining listeners:', listeners.size);
94
+ }
95
+ return removed;
96
+ }
97
+
98
+ // ✅ Debug function to see current listeners
99
+ export function getListenerCount() {
100
+ return listeners.size;
31
101
  }