@spidy092/auth-client 2.0.7 → 2.1.0

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/config.js +0 -1
  2. package/core.js +15 -54
  3. package/package.json +1 -1
  4. package/token.js +53 -31
package/config.js CHANGED
@@ -5,7 +5,6 @@ let config = {
5
5
  redirectUri: null,
6
6
  accountUiUrl: null,
7
7
  isRouter: false, // ✅ Add router flag
8
- usePkce: false,
9
8
  };
10
9
 
11
10
  export function setConfig(customConfig = {}) {
package/core.js CHANGED
@@ -12,7 +12,7 @@ import { getConfig, isRouterMode } from './config';
12
12
 
13
13
  let callbackProcessed = false;
14
14
 
15
- export function login(clientKeyArg, redirectUriArg, options = {}) {
15
+ export function login(clientKeyArg, redirectUriArg) {
16
16
  // ✅ Reset callback state when starting new login
17
17
  resetCallbackState();
18
18
 
@@ -25,14 +25,11 @@ export function login(clientKeyArg, redirectUriArg, options = {}) {
25
25
 
26
26
  const clientKey = clientKeyArg || defaultClientKey;
27
27
  const redirectUri = redirectUriArg || defaultRedirectUri;
28
- const { codeChallenge, codeChallengeMethod, state } = options;
29
28
 
30
29
  console.log('🔄 Smart Login initiated:', {
31
30
  mode: isRouterMode() ? 'ROUTER' : 'CLIENT',
32
31
  clientKey,
33
- redirectUri,
34
- hasPKCE: !!codeChallenge,
35
- hasState: !!state
32
+ redirectUri
36
33
  });
37
34
 
38
35
  if (!clientKey || !redirectUri) {
@@ -44,39 +41,27 @@ export function login(clientKeyArg, redirectUriArg, options = {}) {
44
41
 
45
42
  if (isRouterMode()) {
46
43
  // Router mode: Direct backend authentication
47
- return routerLogin(clientKey, redirectUri, { codeChallenge, codeChallengeMethod, state });
44
+ return routerLogin(clientKey, redirectUri);
48
45
  } else {
49
46
  // Client mode: Redirect to centralized login
50
- return clientLogin(clientKey, redirectUri, { codeChallenge, codeChallengeMethod, state });
47
+ return clientLogin(clientKey, redirectUri);
51
48
  }
52
49
  }
53
50
 
54
51
  // ✅ Router mode: Direct backend call
55
- function routerLogin(clientKey, redirectUri, options = {}) {
52
+ function routerLogin(clientKey, redirectUri) {
56
53
  const { authBaseUrl } = getConfig();
57
- const { codeChallenge, codeChallengeMethod, state } = options;
58
-
59
- // Build URL with PKCE and state parameters
60
- const params = new URLSearchParams({
61
- redirect_uri: redirectUri
62
- });
63
54
 
64
- if (codeChallenge) {
65
- params.append('code_challenge', codeChallenge);
66
- params.append('code_challenge_method', codeChallengeMethod || 'S256');
55
+ const params = new URLSearchParams();
56
+ if (redirectUri) {
57
+ params.append('redirect_uri', redirectUri);
67
58
  }
68
-
69
- if (state) {
70
- params.append('state', state);
71
- }
72
-
73
- const backendLoginUrl = `${authBaseUrl}/login/${clientKey}?${params.toString()}`;
59
+ const query = params.toString();
60
+ const backendLoginUrl = `${authBaseUrl}/login/${clientKey}${query ? `?${query}` : ''}`;
74
61
 
75
62
  console.log('🏭 Router Login: Direct backend authentication', {
76
63
  clientKey,
77
64
  redirectUri,
78
- hasPKCE: !!codeChallenge,
79
- hasState: !!state,
80
65
  backendUrl: backendLoginUrl
81
66
  });
82
67
 
@@ -84,32 +69,20 @@ function routerLogin(clientKey, redirectUri, options = {}) {
84
69
  }
85
70
 
86
71
  // ✅ Client mode: Centralized login
87
- function clientLogin(clientKey, redirectUri, options = {}) {
72
+ function clientLogin(clientKey, redirectUri) {
88
73
  const { accountUiUrl } = getConfig();
89
- const { codeChallenge, codeChallengeMethod, state } = options;
90
74
 
91
- // Build URL with PKCE and state parameters
92
75
  const params = new URLSearchParams({
93
- client: clientKey,
94
- redirect_uri: redirectUri
76
+ client: clientKey
95
77
  });
96
-
97
- if (codeChallenge) {
98
- params.append('code_challenge', codeChallenge);
99
- params.append('code_challenge_method', codeChallengeMethod || 'S256');
100
- }
101
-
102
- if (state) {
103
- params.append('state', state);
78
+ if (redirectUri) {
79
+ params.append('redirect_uri', redirectUri);
104
80
  }
105
-
106
81
  const centralizedLoginUrl = `${accountUiUrl}/login?${params.toString()}`;
107
82
 
108
83
  console.log('🔄 Client Login: Redirecting to centralized login', {
109
84
  clientKey,
110
85
  redirectUri,
111
- hasPKCE: !!codeChallenge,
112
- hasState: !!state,
113
86
  centralizedUrl: centralizedLoginUrl
114
87
  });
115
88
 
@@ -187,23 +160,12 @@ export function handleCallback() {
187
160
  const params = new URLSearchParams(window.location.search);
188
161
  const accessToken = params.get('access_token');
189
162
  const error = params.get('error');
190
- const state = params.get('state');
191
163
 
192
164
  console.log('🔄 Callback handling:', {
193
165
  hasAccessToken: !!accessToken,
194
- error,
195
- hasState: !!state
166
+ error
196
167
  });
197
168
 
198
- // ✅ Validate state parameter
199
- if (state) {
200
- console.warn("⚠️ State returned but validation disabled (demo mode)");
201
-
202
- // Clean up any existing stored state
203
- sessionStorage.removeItem('oauth_state');
204
- sessionStorage.removeItem('pkce_timestamp');
205
- }
206
-
207
169
  // ✅ Prevent duplicate callback processing
208
170
  if (callbackProcessed) {
209
171
  const existingToken = getToken();
@@ -218,7 +180,6 @@ export function handleCallback() {
218
180
  callbackProcessed = true;
219
181
  sessionStorage.removeItem('originalApp');
220
182
  sessionStorage.removeItem('returnUrl');
221
- sessionStorage.removeItem('pkce_code_verifier'); // Clear PKCE verifier after use
222
183
 
223
184
  if (error) {
224
185
  const errorDescription = params.get('error_description') || error;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@spidy092/auth-client",
3
- "version": "2.0.7",
3
+ "version": "2.1.0",
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
@@ -53,7 +53,7 @@ function readAccessToken() {
53
53
  // }
54
54
 
55
55
  // const expires = new Date(Date.now() + COOKIE_MAX_AGE * 1000);
56
-
56
+
57
57
  // try {
58
58
  // document.cookie = `${REFRESH_COOKIE}=${encodeURIComponent(token)}; Path=/; SameSite=Lax${secureAttribute()}; Expires=${expires.toUTCString()}`;
59
59
  // } catch (err) {
@@ -66,14 +66,14 @@ function readAccessToken() {
66
66
  // const match = document.cookie
67
67
  // ?.split('; ')
68
68
  // ?.find((row) => row.startsWith(`${REFRESH_COOKIE}=`));
69
-
69
+
70
70
  // if (match) {
71
71
  // return decodeURIComponent(match.split('=')[1]);
72
72
  // }
73
73
  // } catch (err) {
74
74
  // console.warn('Could not read refresh token:', err);
75
75
  // }
76
-
76
+
77
77
  // return null;
78
78
  // }
79
79
 
@@ -145,55 +145,77 @@ export function clearToken() {
145
145
  });
146
146
  }
147
147
 
148
+ // ========== REFRESH TOKEN STORAGE FOR HTTP DEVELOPMENT ==========
149
+ // In production, refresh tokens should ONLY be in httpOnly cookies set by server
150
+ // For HTTP development (cross-origin cookies don't work), we store in localStorage
151
+ const REFRESH_TOKEN_KEY = 'auth_refresh_token';
152
+
153
+ function isHttpDevelopment() {
154
+ try {
155
+ return typeof window !== 'undefined' &&
156
+ window.location?.protocol === 'http:';
157
+ } catch (err) {
158
+ return false;
159
+ }
160
+ }
161
+
148
162
  export function setRefreshToken(token) {
149
- // ✅ SECURITY: Refresh tokens should ONLY be in httpOnly cookies set by server
150
- // This function should NOT be used - refresh tokens must come from server cookies
151
- // Keeping for backwards compatibility but logging warning
152
-
153
163
  if (!token) {
154
164
  clearRefreshToken();
155
165
  return;
156
166
  }
157
167
 
158
- console.warn('⚠️ SECURITY WARNING: setRefreshToken() called - refresh tokens should only be in httpOnly cookies!');
159
- console.warn('⚠️ Refresh tokens set client-side are insecure and should be removed');
160
-
161
- // ❌ DO NOT store refresh token in client-side storage
162
- // The server sets it in httpOnly cookie, which is the only secure way
163
-
164
- // Only clear any existing client-side storage
165
- try {
166
- sessionStorage.removeItem(REFRESH_COOKIE);
167
- } catch (err) {
168
- // Ignore
168
+ // For HTTP development, store in localStorage (since httpOnly cookies don't work cross-origin)
169
+ if (isHttpDevelopment()) {
170
+ try {
171
+ localStorage.setItem(REFRESH_TOKEN_KEY, token);
172
+ console.log('📦 Refresh token stored in localStorage (HTTP dev mode)');
173
+ } catch (err) {
174
+ console.warn('Could not store refresh token:', err);
175
+ }
176
+ } else {
177
+ // In production (HTTPS), refresh token should be in httpOnly cookie only
178
+ console.log('🔒 Refresh token managed by server httpOnly cookie (production mode)');
169
179
  }
170
180
  }
171
181
 
172
182
  export function getRefreshToken() {
173
- // Refresh tokens are stored in httpOnly cookies by the server
174
- // We cannot read httpOnly cookies from JavaScript - they're only sent with requests
175
- // This function is kept for backwards compatibility but returns null
176
- // The refresh endpoint will automatically use the httpOnly cookie via credentials: 'include'
177
-
178
- // DO NOT try to read refresh token from client-side storage
179
- // httpOnly cookies are not accessible via document.cookie
180
-
181
- console.warn('⚠️ getRefreshToken() called - refresh tokens are in httpOnly cookies and cannot be read from JavaScript');
182
- console.warn('⚠️ The refresh endpoint will automatically use the httpOnly cookie via credentials: "include"');
183
-
184
- return null; // Refresh token is in httpOnly cookie, not accessible to JavaScript
183
+ // For HTTP development, read from localStorage
184
+ if (isHttpDevelopment()) {
185
+ try {
186
+ const token = localStorage.getItem(REFRESH_TOKEN_KEY);
187
+ return token;
188
+ } catch (err) {
189
+ console.warn('Could not read refresh token:', err);
190
+ return null;
191
+ }
192
+ }
193
+
194
+ // In production, refresh token is in httpOnly cookie (not accessible via JS)
195
+ // The refresh endpoint uses credentials: 'include' to send the cookie
196
+ return null;
185
197
  }
186
198
 
187
199
  export function clearRefreshToken() {
200
+ // Clear localStorage (for HTTP dev)
201
+ try {
202
+ localStorage.removeItem(REFRESH_TOKEN_KEY);
203
+ } catch (err) {
204
+ // Ignore
205
+ }
206
+
207
+ // Clear cookie (for production)
188
208
  try {
189
209
  document.cookie = `${REFRESH_COOKIE}=; Path=/; SameSite=Strict${secureAttribute()}; Expires=Thu, 01 Jan 1970 00:00:00 GMT`;
190
210
  } catch (err) {
191
211
  console.warn('Could not clear refresh token cookie:', err);
192
212
  }
213
+
214
+ // Clear sessionStorage
193
215
  try {
194
216
  sessionStorage.removeItem(REFRESH_COOKIE);
195
217
  } catch (err) {
196
- console.warn('Could not clear refresh token from sessionStorage:', err);
218
+ // Ignore
197
219
  }
198
220
  }
199
221