@spidy092/auth-client 2.0.3 → 2.0.5

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 (3) hide show
  1. package/core.js +23 -145
  2. package/package.json +1 -1
  3. package/token.js +15 -47
package/core.js CHANGED
@@ -1,4 +1,5 @@
1
- // auth-client/core.js
1
+ // auth-client/core.js - MINIMAL WORKING VERSION
2
+
2
3
  import {
3
4
  setToken,
4
5
  clearToken,
@@ -9,11 +10,9 @@ import {
9
10
  } from './token';
10
11
  import { getConfig, isRouterMode } from './config';
11
12
 
12
- // ✅ Track callback state with listeners
13
13
  let callbackProcessed = false;
14
14
 
15
- export async function login(clientKeyArg, redirectUriArg) {
16
- // ✅ Reset callback state when starting new login
15
+ export function login(clientKeyArg, redirectUriArg) {
17
16
  resetCallbackState();
18
17
 
19
18
  const {
@@ -36,138 +35,40 @@ export async function login(clientKeyArg, redirectUriArg) {
36
35
  throw new Error('Missing clientKey or redirectUri');
37
36
  }
38
37
 
39
- // Store app info
40
38
  sessionStorage.setItem('originalApp', clientKey);
41
39
  sessionStorage.setItem('returnUrl', redirectUri);
42
40
 
43
- try {
44
- const hasValidSession = await checkExistingTokens();
45
- if (hasValidSession) {
46
- console.log('✅ Valid session found, skipping login redirect');
47
- return getToken();
48
- }
49
- } catch (err) {
50
- console.log('⚠️ No valid session, proceeding with login flow');
51
- }
52
-
53
- // ✅ Smart Router Logic
54
41
  if (isRouterMode()) {
55
- // Router mode: Direct backend authentication
56
42
  return routerLogin(clientKey, redirectUri);
57
43
  } else {
58
- // Client mode: Redirect to centralized login
59
44
  return clientLogin(clientKey, redirectUri);
60
45
  }
61
46
  }
62
47
 
63
- // ✅ Router mode: Direct backend call
64
48
  function routerLogin(clientKey, redirectUri) {
65
49
  const { authBaseUrl } = getConfig();
66
50
  const backendLoginUrl = `${authBaseUrl}/login/${clientKey}?redirect_uri=${encodeURIComponent(redirectUri)}`;
67
51
 
68
- console.log('🏭 Router Login: Direct backend authentication', {
69
- clientKey,
70
- redirectUri,
71
- backendUrl: backendLoginUrl
72
- });
73
-
52
+ console.log('🏭 Router Login:', backendLoginUrl);
74
53
  window.location.href = backendLoginUrl;
75
54
  }
76
55
 
77
-
78
- async function checkExistingTokens() {
79
- const token = getToken();
80
- const refreshTokenValue = getRefreshToken();
81
-
82
- console.log('🔍 Checking existing tokens:', {
83
- hasAccessToken: !!token,
84
- hasRefreshToken: !!refreshTokenValue
85
- });
86
-
87
- // No tokens at all
88
- if (!token && !refreshTokenValue) {
89
- console.log('❌ No tokens found');
90
- return false;
91
- }
92
-
93
- // Have valid access token
94
- if (token && !isTokenExpiredLocal(token)) {
95
- console.log('✅ Valid access token exists');
96
- return true;
97
- }
98
-
99
- // Have refresh token, try to get new access token
100
- if (refreshTokenValue) {
101
- try {
102
- console.log('🔄 Access token expired, attempting refresh...');
103
- const newToken = await refreshToken();
104
- console.log('✅ Token refreshed successfully');
105
- return !!newToken;
106
- } catch (err) {
107
- console.warn('❌ Token refresh failed:', err);
108
- return false;
109
- }
110
- }
111
-
112
- return false;
113
- }
114
-
115
- // ✅ NEW HELPER: Check if token is expired
116
- function isTokenExpiredLocal(token, bufferSeconds = 60) {
117
- if (!token) return true;
118
-
119
- try {
120
- const parts = token.split('.');
121
- if (parts.length !== 3) return true;
122
-
123
- const payload = JSON.parse(atob(parts[1]));
124
-
125
- if (!payload.exp) return true;
126
-
127
- const now = Date.now() / 1000;
128
- const isExpired = payload.exp < (now + bufferSeconds);
129
-
130
- console.log('🕐 Token expiry check:', {
131
- expiresAt: new Date(payload.exp * 1000).toLocaleString(),
132
- now: new Date(now * 1000).toLocaleString(),
133
- isExpired
134
- });
135
-
136
- return isExpired;
137
- } catch (err) {
138
- console.error('❌ Failed to decode token:', err);
139
- return true;
140
- }
141
- }
142
-
143
- // ✅ Client mode: Centralized login
144
56
  function clientLogin(clientKey, redirectUri) {
145
57
  const { accountUiUrl } = getConfig();
146
58
  const centralizedLoginUrl = `${accountUiUrl}/login?client=${clientKey}&redirect_uri=${encodeURIComponent(redirectUri)}`;
147
59
 
148
- console.log('🔄 Client Login: Redirecting to centralized login', {
149
- clientKey,
150
- redirectUri,
151
- centralizedUrl: centralizedLoginUrl
152
- });
153
-
60
+ console.log('🔄 Client Login:', centralizedLoginUrl);
154
61
  window.location.href = centralizedLoginUrl;
155
62
  }
156
63
 
157
64
  export function logout() {
158
- // ✅ Reset callback state on logout
159
65
  resetCallbackState();
160
66
 
161
67
  const { clientKey, authBaseUrl, accountUiUrl } = getConfig();
162
68
  const token = getToken();
163
69
 
164
- console.log('🚪 Smart Logout initiated:', {
165
- mode: isRouterMode() ? 'ROUTER' : 'CLIENT',
166
- clientKey,
167
- hasToken: !!token
168
- });
70
+ console.log('🚪 Smart Logout initiated');
169
71
 
170
- // Clear local storage immediately (this will trigger listeners)
171
72
  clearToken();
172
73
  clearRefreshToken();
173
74
  sessionStorage.removeItem('originalApp');
@@ -180,12 +81,10 @@ export function logout() {
180
81
  }
181
82
  }
182
83
 
183
- // ✅ Router logout
184
84
  async function routerLogout(clientKey, authBaseUrl, accountUiUrl, token) {
185
- console.log('🏭 Enhanced Router Logout with sessionStorage');
85
+ console.log('🏭 Router Logout');
186
86
 
187
87
  const refreshToken = getRefreshToken();
188
- console.log('Refresh token available:', refreshToken ? 'FOUND' : 'MISSING');
189
88
 
190
89
  try {
191
90
  const response = await fetch(`${authBaseUrl}/logout/${clientKey}`, {
@@ -196,19 +95,17 @@ async function routerLogout(clientKey, authBaseUrl, accountUiUrl, token) {
196
95
  'Content-Type': 'application/json'
197
96
  },
198
97
  body: JSON.stringify({
199
- refreshToken: refreshToken // Send in body
98
+ refreshToken: refreshToken
200
99
  })
201
100
  });
202
101
 
203
102
  const data = await response.json();
204
103
  console.log('✅ Logout response:', data);
205
104
 
206
- // Clear stored tokens
207
105
  clearRefreshToken();
208
106
  clearToken();
209
107
 
210
- // Delay before redirect
211
- await new Promise(resolve => setTimeout(resolve, 5000)); // ⏳ wait 5 sec
108
+ await new Promise(resolve => setTimeout(resolve, 5000));
212
109
 
213
110
  if (data.success && data.keycloakLogoutUrl) {
214
111
  window.location.href = data.keycloakLogoutUrl;
@@ -221,16 +118,12 @@ async function routerLogout(clientKey, authBaseUrl, accountUiUrl, token) {
221
118
  clearToken();
222
119
  }
223
120
 
224
- // Delay before fallback redirect
225
- await new Promise(resolve => setTimeout(resolve, 5000)); // ⏳ wait 5 sec
121
+ await new Promise(resolve => setTimeout(resolve, 5000));
226
122
  window.location.href = '/login';
227
123
  }
228
124
 
229
-
230
-
231
- // ✅ Client logout
232
125
  function clientLogout(clientKey, accountUiUrl) {
233
- console.log('🔄 Client Logout: Redirecting to centralized login');
126
+ console.log('🔄 Client Logout');
234
127
  const logoutUrl = `${accountUiUrl}/login?client=${clientKey}&logout=true`;
235
128
  window.location.href = logoutUrl;
236
129
  }
@@ -238,10 +131,10 @@ function clientLogout(clientKey, accountUiUrl) {
238
131
  export function handleCallback() {
239
132
  const params = new URLSearchParams(window.location.search);
240
133
  const accessToken = params.get('access_token');
241
- const refreshToken = params.get('refresh_token'); // CAPTURE THIS
134
+ const refreshToken = params.get('refresh_token');
242
135
  const error = params.get('error');
243
136
 
244
- console.log('🔄 Enhanced callback handling:', {
137
+ console.log('🔄 Callback handling:', {
245
138
  hasAccessToken: !!accessToken,
246
139
  hasRefreshToken: !!refreshToken,
247
140
  error
@@ -263,16 +156,14 @@ export function handleCallback() {
263
156
  if (accessToken) {
264
157
  setToken(accessToken);
265
158
 
266
- // Store refresh token for future refresh calls
267
159
  if (refreshToken) {
268
160
  setRefreshToken(refreshToken);
269
161
  console.log('✅ Refresh token persisted');
270
162
  }
271
163
 
272
- // Clean URL parameters
273
164
  const url = new URL(window.location);
274
165
  url.searchParams.delete('access_token');
275
- url.searchParams.delete('refresh_token'); // Remove this too
166
+ url.searchParams.delete('refresh_token');
276
167
  url.searchParams.delete('state');
277
168
  window.history.replaceState({}, '', url);
278
169
 
@@ -282,27 +173,18 @@ export function handleCallback() {
282
173
  throw new Error('No access token found in callback URL');
283
174
  }
284
175
 
285
-
286
-
287
- // ✅ Reset callback state
288
176
  export function resetCallbackState() {
289
177
  callbackProcessed = false;
290
- console.log('🔄 Callback state reset');
291
178
  }
292
179
 
293
- // auth-client/core.js
294
180
  export async function refreshToken() {
295
181
  const { clientKey, authBaseUrl } = getConfig();
296
- const refreshTokenValue = getRefreshToken(); // ✅ Now checks both cookie & localStorage
182
+ const refreshTokenValue = getRefreshToken();
297
183
 
298
- console.log('🔄 Refreshing token:', {
299
- clientKey,
300
- mode: isRouterMode() ? 'ROUTER' : 'CLIENT',
301
- hasRefreshToken: !!refreshTokenValue
302
- });
184
+ console.log('🔄 Refreshing token');
303
185
 
304
186
  if (!refreshTokenValue) {
305
- console.warn('⚠️ No refresh token available for refresh');
187
+ console.warn('⚠️ No refresh token available');
306
188
  clearToken();
307
189
  throw new Error('No refresh token available');
308
190
  }
@@ -310,13 +192,13 @@ export async function refreshToken() {
310
192
  try {
311
193
  const response = await fetch(`${authBaseUrl}/refresh/${clientKey}`, {
312
194
  method: 'POST',
313
- credentials: 'include', // ✅ Sends cookie if available
195
+ credentials: 'include',
314
196
  headers: {
315
197
  'Content-Type': 'application/json',
316
- 'X-Refresh-Token': refreshTokenValue // ✅ Also send in header as fallback
198
+ 'X-Refresh-Token': refreshTokenValue
317
199
  },
318
200
  body: JSON.stringify({
319
- refreshToken: refreshTokenValue // ✅ Also send in body
201
+ refreshToken: refreshTokenValue
320
202
  })
321
203
  });
322
204
 
@@ -326,27 +208,22 @@ export async function refreshToken() {
326
208
 
327
209
  const { access_token, refresh_token: new_refresh_token } = await response.json();
328
210
 
329
- // ✅ Update access token (triggers listeners)
330
211
  setToken(access_token);
331
-
332
- // ✅ Update refresh token in BOTH storages if backend returned new one
212
+
333
213
  if (new_refresh_token) {
334
214
  setRefreshToken(new_refresh_token);
335
215
  }
336
216
 
337
- console.log('✅ Token refresh successful, listeners notified');
217
+ console.log('✅ Token refresh successful');
338
218
  return access_token;
339
219
  } catch (err) {
340
220
  console.error('❌ Token refresh failed:', err);
341
- // ✅ Clear everything on refresh failure
342
221
  clearToken();
343
222
  clearRefreshToken();
344
223
  throw err;
345
224
  }
346
225
  }
347
226
 
348
-
349
-
350
227
  export async function validateCurrentSession() {
351
228
  try {
352
229
  const { authBaseUrl } = getConfig();
@@ -386,6 +263,7 @@ export async function validateCurrentSession() {
386
263
 
387
264
 
388
265
 
266
+
389
267
  // export async function refreshToken() {
390
268
  // const { clientKey, authBaseUrl } = getConfig();
391
269
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@spidy092/auth-client",
3
- "version": "2.0.3",
3
+ "version": "2.0.5",
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,4 +1,4 @@
1
- // auth-client/token.js - CORRECTED VERSION
1
+ // auth-client/token.js - MINIMAL WORKING VERSION
2
2
 
3
3
  import { jwtDecode } from 'jwt-decode';
4
4
 
@@ -6,7 +6,7 @@ let accessToken = null;
6
6
  const listeners = new Set();
7
7
 
8
8
  const REFRESH_COOKIE = 'account_refresh_token';
9
- const COOKIE_MAX_AGE = 7 * 24 * 60 * 60; // 7 days in seconds
9
+ const COOKIE_MAX_AGE = 7 * 24 * 60 * 60;
10
10
 
11
11
  function secureAttribute() {
12
12
  try {
@@ -18,7 +18,7 @@ function secureAttribute() {
18
18
  }
19
19
  }
20
20
 
21
- // ========== ACCESS TOKEN (localStorage - keeps working) ==========
21
+ // ========== ACCESS TOKEN ==========
22
22
  function writeAccessToken(token) {
23
23
  if (!token) {
24
24
  try {
@@ -45,8 +45,7 @@ function readAccessToken() {
45
45
  }
46
46
  }
47
47
 
48
- // ========== REFRESH TOKEN (Cookie + sessionStorage - REVERTED) ==========
49
-
48
+ // ========== REFRESH TOKEN (KEEP SIMPLE) ==========
50
49
  export function setRefreshToken(token) {
51
50
  if (!token) {
52
51
  clearRefreshToken();
@@ -55,70 +54,38 @@ export function setRefreshToken(token) {
55
54
 
56
55
  const expires = new Date(Date.now() + COOKIE_MAX_AGE * 1000);
57
56
 
58
- // ✅ REVERT: Use SameSite=Lax (NOT Strict) for SSO to work
59
57
  try {
60
58
  document.cookie = `${REFRESH_COOKIE}=${encodeURIComponent(token)}; Path=/; SameSite=Lax${secureAttribute()}; Expires=${expires.toUTCString()}`;
61
- console.log('✅ Refresh token cookie set (SameSite=Lax for SSO)');
62
- } catch (err) {
63
- console.warn('Could not persist refresh token cookie:', err);
64
- }
65
-
66
- // ✅ REVERT: Keep sessionStorage (NOT localStorage) as fallback
67
- try {
68
- sessionStorage.setItem(REFRESH_COOKIE, token);
69
- console.log('✅ Refresh token sessionStorage backup set');
70
59
  } catch (err) {
71
- console.warn('Could not persist refresh token to sessionStorage:', err);
60
+ console.warn('Could not set refresh token:', err);
72
61
  }
73
62
  }
74
63
 
75
64
  export function getRefreshToken() {
76
- // Prefer cookie to align with server expectations
77
- let cookieMatch = null;
78
65
  try {
79
- cookieMatch = document.cookie
66
+ const match = document.cookie
80
67
  ?.split('; ')
81
68
  ?.find((row) => row.startsWith(`${REFRESH_COOKIE}=`));
82
- } catch (err) {
83
- cookieMatch = null;
84
- }
85
-
86
- if (cookieMatch) {
87
- console.log('✅ Retrieved refresh token from cookie');
88
- return decodeURIComponent(cookieMatch.split('=')[1]);
89
- }
90
-
91
- // ✅ REVERT: Fallback to sessionStorage (NOT localStorage)
92
- try {
93
- const token = sessionStorage.getItem(REFRESH_COOKIE);
94
- if (token) {
95
- console.log('✅ Retrieved refresh token from sessionStorage (fallback)');
69
+
70
+ if (match) {
71
+ return decodeURIComponent(match.split('=')[1]);
96
72
  }
97
- return token;
98
73
  } catch (err) {
99
- console.warn('Could not read refresh token from sessionStorage:', err);
100
- return null;
74
+ console.warn('Could not read refresh token:', err);
101
75
  }
76
+
77
+ return null;
102
78
  }
103
79
 
104
80
  export function clearRefreshToken() {
105
- // ✅ REVERT: Clear with SameSite=Lax
106
81
  try {
107
82
  document.cookie = `${REFRESH_COOKIE}=; Path=/; SameSite=Lax${secureAttribute()}; Expires=Thu, 01 Jan 1970 00:00:00 GMT`;
108
83
  } catch (err) {
109
- console.warn('Could not clear refresh token cookie:', err);
110
- }
111
-
112
- // ✅ REVERT: Clear sessionStorage (NOT localStorage)
113
- try {
114
- sessionStorage.removeItem(REFRESH_COOKIE);
115
- } catch (err) {
116
- console.warn('Could not clear refresh token from sessionStorage:', err);
84
+ console.warn('Could not clear refresh token:', err);
117
85
  }
118
86
  }
119
87
 
120
- // ========== ACCESS TOKEN FUNCTIONS (unchanged) ==========
121
-
88
+ // ========== ACCESS TOKEN FUNCTIONS ==========
122
89
  function decode(token) {
123
90
  try {
124
91
  return jwtDecode(token);
@@ -203,6 +170,7 @@ export function isAuthenticated() {
203
170
 
204
171
 
205
172
 
173
+
206
174
  // // auth-client/token.js
207
175
  // import { jwtDecode } from 'jwt-decode';
208
176