@arow-software/auth-client 1.3.0 → 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.
package/README.md CHANGED
@@ -2,9 +2,50 @@
2
2
 
3
3
  Reusable authentication package for ArowAuth SSO integration. Provides React context, hooks, and utilities for seamless SSO authentication with automatic token refresh.
4
4
 
5
+ ## ⚠️ v2.0.0 Breaking Changes (PKCE Flow)
6
+
7
+ **v2.0.0** migrates from OAuth 2.0 Implicit Flow to **Authorization Code + PKCE** for enhanced security.
8
+
9
+ ### What Changed
10
+
11
+ - **OAuth Flow:** Changed from `response_type=token` (implicit) to `response_type=code` (authorization code with PKCE)
12
+ - **Security:** Tokens no longer exposed in URL hash fragment; authorization code exchanged server-side for tokens
13
+ - **PKCE:** Code verifier/challenge pairs automatically generated and verified
14
+ - **API Change:** `login()` method is now `async` (returns `Promise<void>`)
15
+
16
+ ### Migration Guide
17
+
18
+ **Before (v1.x):**
19
+ ```tsx
20
+ const { login } = useAuth();
21
+ login('/dashboard'); // Synchronous
22
+ ```
23
+
24
+ **After (v2.x):**
25
+ ```tsx
26
+ const { login } = useAuth();
27
+ await login('/dashboard'); // Now async
28
+ // OR
29
+ login('/dashboard'); // Fire-and-forget still works
30
+ ```
31
+
32
+ ### Backward Compatibility
33
+
34
+ v2.0 maintains **backward compatibility** with v1.x implicit flow during transition:
35
+ - Still parses tokens from URL hash fragment as fallback
36
+ - Existing v1.x clients can continue using the library without changes
37
+ - Prioritizes new PKCE flow (query param `code`) over legacy implicit flow (hash fragment tokens)
38
+
39
+ ### Why PKCE?
40
+
41
+ - **More Secure:** Eliminates token exposure in browser history and referrer headers
42
+ - **Industry Standard:** OAuth 2.1 deprecates implicit flow in favor of authorization code + PKCE
43
+ - **Mobile-Ready:** PKCE is required for native mobile apps and recommended for SPAs
44
+
5
45
  ## Features
6
46
 
7
- - 🔐 **Token Management** - Secure storage, automatic refresh, JWT decoding
47
+ - 🔐 **PKCE Flow** - Secure Authorization Code + PKCE (RFC 7636)
48
+ - 🔒 **Token Management** - Secure storage, automatic refresh, JWT decoding
8
49
  - 🔄 **API Interceptors** - Axios interceptors with 401 handling and request queuing
9
50
  - ⚛️ **React Integration** - Context provider and hooks for easy auth state management
10
51
  - 🎯 **TypeScript** - Full type definitions included
@@ -133,7 +174,7 @@ Returns an object with:
133
174
  isAuthenticated: boolean; // Whether user is logged in
134
175
  isLoading: boolean; // Initial auth check in progress
135
176
  error: string | null; // Any auth error message
136
- login: (redirectPath?: string) => void; // Redirect to SSO login
177
+ login: (redirectPath?: string) => Promise<void>; // Redirect to SSO login (async in v2.0+)
137
178
  logout: () => Promise<void>; // Clear tokens and logout
138
179
  refreshUser: () => Promise<void>; // Refresh user from token
139
180
  }
@@ -230,7 +271,9 @@ function CallbackPage() {
230
271
  const navigate = useNavigate();
231
272
 
232
273
  useEffect(() => {
233
- // AuthProvider automatically handles token extraction from URL hash
274
+ // AuthProvider automatically handles:
275
+ // - PKCE code exchange (v2.x): extracts code from query params, exchanges for tokens
276
+ // - Implicit flow (v1.x): extracts tokens from URL hash (backward compatibility)
234
277
  // Just wait for auth to complete and redirect
235
278
  if (!isLoading) {
236
279
  if (isAuthenticated) {
package/dist/index.d.mts CHANGED
@@ -57,7 +57,7 @@ interface AuthState {
57
57
  * Auth context value including actions
58
58
  */
59
59
  interface AuthContextValue extends AuthState {
60
- login: (redirectPath?: string) => void;
60
+ login: (redirectPath?: string) => Promise<void>;
61
61
  logout: () => Promise<void>;
62
62
  refreshUser: () => Promise<void>;
63
63
  }
@@ -66,10 +66,16 @@ interface AuthContextValue extends AuthState {
66
66
  */
67
67
  interface AuthConfig {
68
68
  /**
69
- * Base URL of the ArowAuth SSO server
69
+ * Base URL of the ArowAuth SSO UI (used for login redirects)
70
70
  * @example "https://sso.arowsoftware.co.uk"
71
71
  */
72
72
  ssoBaseUrl: string;
73
+ /**
74
+ * Base URL of the ArowAuth API (used for token exchange, refresh, etc.)
75
+ * If not provided, falls back to ssoBaseUrl for backward compatibility.
76
+ * @example "https://sso-api.arowsoftware.co.uk"
77
+ */
78
+ ssoApiUrl?: string;
73
79
  /**
74
80
  * Client ID registered with ArowAuth
75
81
  * @example "arowtrades"
@@ -176,6 +182,23 @@ declare function cancelProactiveRefresh(): void;
176
182
  */
177
183
  declare function scheduleProactiveRefresh(onRefreshed?: (tokens: TokenPair) => void, onFailed?: () => void): void;
178
184
 
185
+ /**
186
+ * PKCE (Proof Key for Code Exchange) helper functions for OAuth 2.0 Authorization Code Flow
187
+ *
188
+ * RFC 7636: https://datatracker.ietf.org/doc/html/rfc7636
189
+ */
190
+ /**
191
+ * Generate a cryptographically random code verifier
192
+ * Returns a base64url-encoded string of 32 random bytes (43 characters)
193
+ */
194
+ declare function generateCodeVerifier(): string;
195
+ /**
196
+ * Generate a code challenge from a code verifier using SHA-256
197
+ * @param verifier - The code verifier string
198
+ * @returns Promise resolving to the base64url-encoded SHA-256 hash
199
+ */
200
+ declare function generateCodeChallenge(verifier: string): Promise<string>;
201
+
179
202
  /**
180
203
  * Create and configure axios instance with auth interceptors
181
204
  */
@@ -262,4 +285,4 @@ declare function useUser(): User | null;
262
285
  */
263
286
  declare function useAuthClient(): AxiosInstance;
264
287
 
265
- export { type AuthConfig, AuthContext, type AuthContextValue, AuthProvider, type AuthProviderProps, type AuthState, type JwtPayload, type TokenPair, type User, cancelProactiveRefresh, clearTokens, createApiClient, createAuthClient, decodeJwt, getAccessToken, getRefreshToken, getTokenExpiry, getUserFromToken, getValidAccessToken, hasValidToken, initTokenManager, isTokenExpired, refreshTokens, scheduleProactiveRefresh, setTokens, useAuth, useAuthClient, useIsAuthenticated, useUser };
288
+ export { type AuthConfig, AuthContext, type AuthContextValue, AuthProvider, type AuthProviderProps, type AuthState, type JwtPayload, type TokenPair, type User, cancelProactiveRefresh, clearTokens, createApiClient, createAuthClient, decodeJwt, generateCodeChallenge, generateCodeVerifier, getAccessToken, getRefreshToken, getTokenExpiry, getUserFromToken, getValidAccessToken, hasValidToken, initTokenManager, isTokenExpired, refreshTokens, scheduleProactiveRefresh, setTokens, useAuth, useAuthClient, useIsAuthenticated, useUser };
package/dist/index.d.ts CHANGED
@@ -57,7 +57,7 @@ interface AuthState {
57
57
  * Auth context value including actions
58
58
  */
59
59
  interface AuthContextValue extends AuthState {
60
- login: (redirectPath?: string) => void;
60
+ login: (redirectPath?: string) => Promise<void>;
61
61
  logout: () => Promise<void>;
62
62
  refreshUser: () => Promise<void>;
63
63
  }
@@ -66,10 +66,16 @@ interface AuthContextValue extends AuthState {
66
66
  */
67
67
  interface AuthConfig {
68
68
  /**
69
- * Base URL of the ArowAuth SSO server
69
+ * Base URL of the ArowAuth SSO UI (used for login redirects)
70
70
  * @example "https://sso.arowsoftware.co.uk"
71
71
  */
72
72
  ssoBaseUrl: string;
73
+ /**
74
+ * Base URL of the ArowAuth API (used for token exchange, refresh, etc.)
75
+ * If not provided, falls back to ssoBaseUrl for backward compatibility.
76
+ * @example "https://sso-api.arowsoftware.co.uk"
77
+ */
78
+ ssoApiUrl?: string;
73
79
  /**
74
80
  * Client ID registered with ArowAuth
75
81
  * @example "arowtrades"
@@ -176,6 +182,23 @@ declare function cancelProactiveRefresh(): void;
176
182
  */
177
183
  declare function scheduleProactiveRefresh(onRefreshed?: (tokens: TokenPair) => void, onFailed?: () => void): void;
178
184
 
185
+ /**
186
+ * PKCE (Proof Key for Code Exchange) helper functions for OAuth 2.0 Authorization Code Flow
187
+ *
188
+ * RFC 7636: https://datatracker.ietf.org/doc/html/rfc7636
189
+ */
190
+ /**
191
+ * Generate a cryptographically random code verifier
192
+ * Returns a base64url-encoded string of 32 random bytes (43 characters)
193
+ */
194
+ declare function generateCodeVerifier(): string;
195
+ /**
196
+ * Generate a code challenge from a code verifier using SHA-256
197
+ * @param verifier - The code verifier string
198
+ * @returns Promise resolving to the base64url-encoded SHA-256 hash
199
+ */
200
+ declare function generateCodeChallenge(verifier: string): Promise<string>;
201
+
179
202
  /**
180
203
  * Create and configure axios instance with auth interceptors
181
204
  */
@@ -262,4 +285,4 @@ declare function useUser(): User | null;
262
285
  */
263
286
  declare function useAuthClient(): AxiosInstance;
264
287
 
265
- export { type AuthConfig, AuthContext, type AuthContextValue, AuthProvider, type AuthProviderProps, type AuthState, type JwtPayload, type TokenPair, type User, cancelProactiveRefresh, clearTokens, createApiClient, createAuthClient, decodeJwt, getAccessToken, getRefreshToken, getTokenExpiry, getUserFromToken, getValidAccessToken, hasValidToken, initTokenManager, isTokenExpired, refreshTokens, scheduleProactiveRefresh, setTokens, useAuth, useAuthClient, useIsAuthenticated, useUser };
288
+ export { type AuthConfig, AuthContext, type AuthContextValue, AuthProvider, type AuthProviderProps, type AuthState, type JwtPayload, type TokenPair, type User, cancelProactiveRefresh, clearTokens, createApiClient, createAuthClient, decodeJwt, generateCodeChallenge, generateCodeVerifier, getAccessToken, getRefreshToken, getTokenExpiry, getUserFromToken, getValidAccessToken, hasValidToken, initTokenManager, isTokenExpired, refreshTokens, scheduleProactiveRefresh, setTokens, useAuth, useAuthClient, useIsAuthenticated, useUser };
package/dist/index.js CHANGED
@@ -126,7 +126,7 @@ async function refreshTokens() {
126
126
  async function performRefresh(refreshToken) {
127
127
  if (!config) return null;
128
128
  try {
129
- const response = await fetch(`${config.ssoBaseUrl}/api/auth/refresh`, {
129
+ const response = await fetch(`${config.ssoApiUrl || config.ssoBaseUrl}/api/auth/refresh`, {
130
130
  method: "POST",
131
131
  headers: {
132
132
  "Content-Type": "application/json"
@@ -187,6 +187,24 @@ function scheduleProactiveRefresh(onRefreshed, onFailed) {
187
187
  }, delaySeconds * 1e3);
188
188
  }
189
189
 
190
+ // src/pkce.ts
191
+ function generateCodeVerifier() {
192
+ const array = new Uint8Array(32);
193
+ crypto.getRandomValues(array);
194
+ return base64UrlEncode(array);
195
+ }
196
+ async function generateCodeChallenge(verifier) {
197
+ const encoder = new TextEncoder();
198
+ const data = encoder.encode(verifier);
199
+ const hash = await crypto.subtle.digest("SHA-256", data);
200
+ return base64UrlEncode(new Uint8Array(hash));
201
+ }
202
+ function base64UrlEncode(bytes) {
203
+ let str = "";
204
+ bytes.forEach((b) => str += String.fromCharCode(b));
205
+ return btoa(str).replace(/\+/g, "-").replace(/\//g, "_").replace(/=+$/, "");
206
+ }
207
+
190
208
  // src/apiInterceptor.ts
191
209
  var isRefreshing2 = false;
192
210
  var requestQueue = [];
@@ -300,19 +318,70 @@ function parseUserFromToken(token) {
300
318
  permissions: payload.permissions
301
319
  };
302
320
  }
303
- function buildAuthUrl(ssoBaseUrl, clientId, redirectUri, scopes = ["openid", "email", "profile"], redirectPath) {
321
+ async function buildAuthUrl(ssoBaseUrl, clientId, redirectUri, scopes = ["openid", "email", "profile"], redirectPath) {
304
322
  const finalRedirectUri = redirectUri || `${window.location.origin}/callback`;
305
323
  if (redirectPath) {
306
324
  sessionStorage.setItem("arowauth_redirect_path", redirectPath);
307
325
  }
326
+ const codeVerifier = generateCodeVerifier();
327
+ const codeChallenge = await generateCodeChallenge(codeVerifier);
328
+ sessionStorage.setItem("arow_pkce_code_verifier", codeVerifier);
308
329
  const params = new URLSearchParams({
309
330
  client_id: clientId,
310
331
  redirect_uri: finalRedirectUri,
311
- response_type: "token",
312
- scope: scopes.join(" ")
332
+ response_type: "code",
333
+ scope: scopes.join(" "),
334
+ code_challenge: codeChallenge,
335
+ code_challenge_method: "S256"
313
336
  });
314
337
  return `${ssoBaseUrl}/oauth/authorize?${params.toString()}`;
315
338
  }
339
+ function parseCodeFromQuery() {
340
+ if (typeof window === "undefined") return null;
341
+ const params = new URLSearchParams(window.location.search);
342
+ const code = params.get("code");
343
+ if (!code) return null;
344
+ return {
345
+ code,
346
+ state: params.get("state") || void 0
347
+ };
348
+ }
349
+ async function exchangeCodeForTokens(ssoApiUrl, clientId, redirectUri, code) {
350
+ try {
351
+ const codeVerifier = sessionStorage.getItem("arow_pkce_code_verifier");
352
+ if (!codeVerifier) {
353
+ throw new Error("Code verifier not found in session storage");
354
+ }
355
+ sessionStorage.removeItem("arow_pkce_code_verifier");
356
+ const body = new URLSearchParams({
357
+ grant_type: "authorization_code",
358
+ code,
359
+ client_id: clientId,
360
+ redirect_uri: redirectUri,
361
+ code_verifier: codeVerifier
362
+ });
363
+ const response = await fetch(`${ssoApiUrl}/oauth/token`, {
364
+ method: "POST",
365
+ headers: {
366
+ "Content-Type": "application/x-www-form-urlencoded"
367
+ },
368
+ body: body.toString()
369
+ });
370
+ if (!response.ok) {
371
+ throw new Error(`Token exchange failed: ${response.status} ${response.statusText}`);
372
+ }
373
+ const data = await response.json();
374
+ return {
375
+ accessToken: data.access_token || data.accessToken,
376
+ refreshToken: data.refresh_token || data.refreshToken,
377
+ expiresIn: data.expires_in || data.expiresIn,
378
+ tokenType: data.token_type || data.tokenType || "Bearer"
379
+ };
380
+ } catch (error) {
381
+ console.error("Failed to exchange code for tokens:", error);
382
+ return null;
383
+ }
384
+ }
316
385
  function parseTokensFromHash() {
317
386
  if (typeof window === "undefined") return null;
318
387
  const hash = window.location.hash;
@@ -349,7 +418,7 @@ function AuthProvider(props) {
349
418
  onLogout
350
419
  };
351
420
  initTokenManager(fullConfig);
352
- }, [config2.ssoBaseUrl, config2.clientId, config2.apiBaseUrl, onTokenRefresh, onAuthError, onLogout]);
421
+ }, [config2.ssoBaseUrl, config2.ssoApiUrl, config2.clientId, config2.apiBaseUrl, onTokenRefresh, onAuthError, onLogout]);
353
422
  react.useEffect(() => {
354
423
  const startProactive = () => {
355
424
  scheduleProactiveRefresh(
@@ -365,6 +434,44 @@ function AuthProvider(props) {
365
434
  };
366
435
  const initAuth = async () => {
367
436
  try {
437
+ const codeData = parseCodeFromQuery();
438
+ if (codeData) {
439
+ const finalRedirectUri = config2.redirectUri || `${window.location.origin}/callback`;
440
+ const tokens = await exchangeCodeForTokens(
441
+ config2.ssoApiUrl || config2.ssoBaseUrl,
442
+ config2.clientId,
443
+ finalRedirectUri,
444
+ codeData.code
445
+ );
446
+ if (tokens) {
447
+ setTokens(tokens.accessToken, tokens.refreshToken);
448
+ const cleanUrl = window.location.pathname;
449
+ window.history.replaceState(null, "", cleanUrl);
450
+ const redirectPath = sessionStorage.getItem("arowauth_redirect_path");
451
+ if (redirectPath) {
452
+ sessionStorage.removeItem("arowauth_redirect_path");
453
+ window.history.replaceState(null, "", redirectPath);
454
+ }
455
+ onTokenRefresh?.(tokens);
456
+ startProactive();
457
+ const user = parseUserFromToken(tokens.accessToken);
458
+ setState({
459
+ user,
460
+ isAuthenticated: true,
461
+ isLoading: false,
462
+ error: null
463
+ });
464
+ return;
465
+ } else {
466
+ setState({
467
+ user: null,
468
+ isAuthenticated: false,
469
+ isLoading: false,
470
+ error: "Failed to exchange authorization code for tokens"
471
+ });
472
+ return;
473
+ }
474
+ }
368
475
  const hashTokens = parseTokensFromHash();
369
476
  if (hashTokens) {
370
477
  setTokens(hashTokens.accessToken, hashTokens.refreshToken);
@@ -423,8 +530,8 @@ function AuthProvider(props) {
423
530
  cancelProactiveRefresh();
424
531
  };
425
532
  }, [onTokenRefresh]);
426
- const login = react.useCallback((redirectPath) => {
427
- const authUrl = buildAuthUrl(
533
+ const login = react.useCallback(async (redirectPath) => {
534
+ const authUrl = await buildAuthUrl(
428
535
  config2.ssoBaseUrl,
429
536
  config2.clientId,
430
537
  config2.redirectUri,
@@ -587,6 +694,8 @@ exports.clearTokens = clearTokens;
587
694
  exports.createApiClient = createApiClient;
588
695
  exports.createAuthClient = createAuthClient;
589
696
  exports.decodeJwt = decodeJwt;
697
+ exports.generateCodeChallenge = generateCodeChallenge;
698
+ exports.generateCodeVerifier = generateCodeVerifier;
590
699
  exports.getAccessToken = getAccessToken;
591
700
  exports.getRefreshToken = getRefreshToken;
592
701
  exports.getTokenExpiry = getTokenExpiry;
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/tokenManager.ts","../src/apiInterceptor.ts","../src/AuthProvider.tsx","../src/hooks/useAuth.ts","../src/hooks/useAuthClient.ts"],"names":["isRefreshing","config","createContext","useState","useEffect","useCallback","useMemo","useContext","requestQueue","processQueue"],"mappings":"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","file":"index.js","sourcesContent":["import type { JwtPayload, TokenPair, AuthConfig } from './types';\n\nconst DEFAULT_STORAGE_PREFIX = 'arowauth';\nconst ACCESS_TOKEN_KEY = 'access_token';\nconst REFRESH_TOKEN_KEY = 'refresh_token';\nconst TOKEN_EXPIRY_KEY = 'token_expiry';\n\n// Buffer time before expiry to trigger refresh (5 minutes for isTokenExpired checks)\nconst EXPIRY_BUFFER_SECONDS = 300;\n\n// Proactive refresh fires 30 seconds before expiry\nconst PROACTIVE_REFRESH_BUFFER_SECONDS = 30;\n\nlet config: AuthConfig | null = null;\nlet isRefreshing = false;\nlet refreshPromise: Promise<TokenPair | null> | null = null;\nlet proactiveRefreshTimer: ReturnType<typeof setTimeout> | null = null;\n\n/**\n * Initialize token manager with configuration\n */\nexport function initTokenManager(authConfig: AuthConfig): void {\n config = authConfig;\n}\n\n/**\n * Get the storage instance (localStorage or sessionStorage)\n */\nfunction getStorage(): Storage {\n if (typeof window === 'undefined') {\n // SSR fallback - return a no-op storage\n return {\n getItem: () => null,\n setItem: () => {},\n removeItem: () => {},\n clear: () => {},\n key: () => null,\n length: 0,\n };\n }\n return config?.useSessionStorage ? sessionStorage : localStorage;\n}\n\n/**\n * Get storage key with prefix\n */\nfunction getKey(key: string): string {\n const prefix = config?.storagePrefix || DEFAULT_STORAGE_PREFIX;\n return `${prefix}_${key}`;\n}\n\n/**\n * Decode a JWT token without verification\n */\nexport function decodeJwt(token: string): JwtPayload | null {\n try {\n const parts = token.split('.');\n if (parts.length !== 3) return null;\n \n const payload = parts[1];\n // Handle URL-safe base64\n const base64 = payload.replace(/-/g, '+').replace(/_/g, '/');\n const jsonPayload = decodeURIComponent(\n atob(base64)\n .split('')\n .map((c) => '%' + ('00' + c.charCodeAt(0).toString(16)).slice(-2))\n .join('')\n );\n \n return JSON.parse(jsonPayload) as JwtPayload;\n } catch {\n return null;\n }\n}\n\n/**\n * Get the access token from storage\n */\nexport function getAccessToken(): string | null {\n return getStorage().getItem(getKey(ACCESS_TOKEN_KEY));\n}\n\n/**\n * Get the refresh token from storage\n */\nexport function getRefreshToken(): string | null {\n return getStorage().getItem(getKey(REFRESH_TOKEN_KEY));\n}\n\n/**\n * Get the stored token expiry timestamp (seconds since epoch)\n */\nexport function getTokenExpiry(): number | null {\n const expiry = getStorage().getItem(getKey(TOKEN_EXPIRY_KEY));\n return expiry ? parseInt(expiry, 10) : null;\n}\n\n/**\n * Store tokens in storage, including the expiry timestamp decoded from the JWT\n */\nexport function setTokens(accessToken: string, refreshToken: string): void {\n const storage = getStorage();\n storage.setItem(getKey(ACCESS_TOKEN_KEY), accessToken);\n storage.setItem(getKey(REFRESH_TOKEN_KEY), refreshToken);\n\n // Persist expiry from JWT exp claim\n const payload = decodeJwt(accessToken);\n if (payload?.exp) {\n storage.setItem(getKey(TOKEN_EXPIRY_KEY), String(payload.exp));\n }\n}\n\n/**\n * Clear all tokens from storage\n */\nexport function clearTokens(): void {\n const storage = getStorage();\n storage.removeItem(getKey(ACCESS_TOKEN_KEY));\n storage.removeItem(getKey(REFRESH_TOKEN_KEY));\n storage.removeItem(getKey(TOKEN_EXPIRY_KEY));\n cancelProactiveRefresh();\n}\n\n/**\n * Check if the access token is expired or about to expire\n */\nexport function isTokenExpired(token?: string | null): boolean {\n const accessToken = token ?? getAccessToken();\n if (!accessToken) return true;\n \n const payload = decodeJwt(accessToken);\n if (!payload || !payload.exp) return true;\n \n // Check if token expires within buffer period\n const now = Math.floor(Date.now() / 1000);\n return payload.exp <= now + EXPIRY_BUFFER_SECONDS;\n}\n\n/**\n * Check if we have a valid (non-expired) access token\n */\nexport function hasValidToken(): boolean {\n const token = getAccessToken();\n return token !== null && !isTokenExpired(token);\n}\n\n/**\n * Get user info from the current access token\n */\nexport function getUserFromToken(): JwtPayload | null {\n const token = getAccessToken();\n if (!token) return null;\n return decodeJwt(token);\n}\n\n/**\n * Refresh tokens using the refresh token\n * Handles concurrent refresh requests by returning the same promise\n */\nexport async function refreshTokens(): Promise<TokenPair | null> {\n if (!config) {\n throw new Error('TokenManager not initialized. Call initTokenManager first.');\n }\n\n const refreshToken = getRefreshToken();\n if (!refreshToken) {\n clearTokens();\n return null;\n }\n\n // If already refreshing, return the existing promise\n if (isRefreshing && refreshPromise) {\n return refreshPromise;\n }\n\n isRefreshing = true;\n refreshPromise = performRefresh(refreshToken);\n\n try {\n const result = await refreshPromise;\n return result;\n } finally {\n isRefreshing = false;\n refreshPromise = null;\n }\n}\n\n/**\n * Perform the actual token refresh request\n */\nasync function performRefresh(refreshToken: string): Promise<TokenPair | null> {\n if (!config) return null;\n\n try {\n const response = await fetch(`${config.ssoBaseUrl}/api/auth/refresh`, {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json',\n },\n body: JSON.stringify({ refreshToken }),\n });\n\n if (!response.ok) {\n clearTokens();\n config.onAuthError?.(new Error('Token refresh failed'));\n return null;\n }\n\n const data = await response.json();\n const tokens: TokenPair = {\n accessToken: data.accessToken || data.access_token,\n refreshToken: data.refreshToken || data.refresh_token,\n expiresIn: data.expiresIn || data.expires_in,\n tokenType: data.tokenType || data.token_type || 'Bearer',\n };\n\n setTokens(tokens.accessToken, tokens.refreshToken);\n config.onTokenRefresh?.(tokens);\n\n return tokens;\n } catch (error) {\n clearTokens();\n config.onAuthError?.(error instanceof Error ? error : new Error('Token refresh failed'));\n return null;\n }\n}\n\n/**\n * Get a valid access token, refreshing if necessary\n */\nexport async function getValidAccessToken(): Promise<string | null> {\n const token = getAccessToken();\n \n if (token && !isTokenExpired(token)) {\n return token;\n }\n\n const refreshed = await refreshTokens();\n return refreshed?.accessToken ?? null;\n}\n\n/**\n * Cancel any pending proactive refresh timer\n */\nexport function cancelProactiveRefresh(): void {\n if (proactiveRefreshTimer !== null) {\n clearTimeout(proactiveRefreshTimer);\n proactiveRefreshTimer = null;\n }\n}\n\n/**\n * Schedule a proactive token refresh ~30 seconds before expiry.\n * Calls `onRefreshed` with the new token pair on success so the\n * AuthProvider can update React state without a re-mount.\n */\nexport function scheduleProactiveRefresh(\n onRefreshed?: (tokens: TokenPair) => void,\n onFailed?: () => void,\n): void {\n cancelProactiveRefresh();\n\n const expiry = getTokenExpiry();\n if (!expiry) return;\n\n const now = Math.floor(Date.now() / 1000);\n const delaySeconds = expiry - now - PROACTIVE_REFRESH_BUFFER_SECONDS;\n\n // If already past the proactive window, don't schedule (the normal\n // isTokenExpired / 401 fallback will handle it)\n if (delaySeconds <= 0) return;\n\n proactiveRefreshTimer = setTimeout(async () => {\n proactiveRefreshTimer = null;\n const tokens = await refreshTokens();\n if (tokens) {\n // Re-schedule for the next cycle\n scheduleProactiveRefresh(onRefreshed, onFailed);\n onRefreshed?.(tokens);\n } else {\n onFailed?.();\n }\n }, delaySeconds * 1000);\n}\n","import type { AxiosInstance, InternalAxiosRequestConfig, AxiosResponse, AxiosError } from 'axios';\nimport { getAccessToken, getValidAccessToken, clearTokens } from './tokenManager';\nimport type { AuthConfig } from './types';\n\ninterface QueuedRequest {\n resolve: (token: string | null) => void;\n reject: (error: Error) => void;\n}\n\nlet isRefreshing = false;\nlet requestQueue: QueuedRequest[] = [];\n\n/**\n * Process queued requests after token refresh\n */\nfunction processQueue(token: string | null, error: Error | null = null): void {\n requestQueue.forEach((request) => {\n if (error) {\n request.reject(error);\n } else {\n request.resolve(token);\n }\n });\n requestQueue = [];\n}\n\n/**\n * Create and configure axios instance with auth interceptors\n */\nexport function createAuthClient(\n axiosInstance: AxiosInstance,\n config: AuthConfig\n): AxiosInstance {\n // Request interceptor - attach Bearer token\n axiosInstance.interceptors.request.use(\n async (requestConfig: InternalAxiosRequestConfig): Promise<InternalAxiosRequestConfig> => {\n // Skip auth for refresh endpoint to avoid infinite loop\n if (requestConfig.url?.includes('/api/auth/refresh')) {\n return requestConfig;\n }\n\n const token = getAccessToken();\n if (token) {\n requestConfig.headers = requestConfig.headers || {};\n requestConfig.headers.Authorization = `Bearer ${token}`;\n }\n return requestConfig;\n },\n (error: unknown) => Promise.reject(error)\n );\n\n // Response interceptor - handle 401 and refresh token\n axiosInstance.interceptors.response.use(\n (response: AxiosResponse) => response,\n async (error: AxiosError): Promise<AxiosResponse> => {\n const originalRequest = error.config as InternalAxiosRequestConfig & {\n _retry?: boolean;\n };\n\n // Only handle 401 errors\n if (error.response?.status !== 401) {\n return Promise.reject(error);\n }\n\n // Don't retry if already retried or no config\n if (originalRequest._retry || !originalRequest) {\n clearTokens();\n config.onAuthError?.(new Error('Authentication failed'));\n return Promise.reject(error);\n }\n\n // Don't retry refresh endpoint\n if (originalRequest.url?.includes('/api/auth/refresh')) {\n clearTokens();\n config.onAuthError?.(new Error('Token refresh failed'));\n return Promise.reject(error);\n }\n\n // If already refreshing, queue this request\n if (isRefreshing) {\n return new Promise((resolve, reject) => {\n requestQueue.push({\n resolve: (token) => {\n if (token) {\n originalRequest.headers = originalRequest.headers || {};\n originalRequest.headers.Authorization = `Bearer ${token}`;\n resolve(axiosInstance(originalRequest));\n } else {\n reject(new Error('Token refresh failed'));\n }\n },\n reject,\n });\n });\n }\n\n originalRequest._retry = true;\n isRefreshing = true;\n\n try {\n const token = await getValidAccessToken();\n \n if (!token) {\n processQueue(null, new Error('Token refresh failed'));\n clearTokens();\n config.onAuthError?.(new Error('Token refresh failed'));\n return Promise.reject(error);\n }\n\n processQueue(token);\n \n originalRequest.headers = originalRequest.headers || {};\n originalRequest.headers.Authorization = `Bearer ${token}`;\n \n return axiosInstance(originalRequest);\n } catch (refreshError) {\n processQueue(null, refreshError instanceof Error ? refreshError : new Error('Token refresh failed'));\n clearTokens();\n config.onAuthError?.(refreshError instanceof Error ? refreshError : new Error('Token refresh failed'));\n return Promise.reject(refreshError);\n } finally {\n isRefreshing = false;\n }\n }\n );\n\n return axiosInstance;\n}\n\n/**\n * Create a new axios instance with auth interceptors\n */\nexport function createApiClient(config: AuthConfig): AxiosInstance {\n // Dynamic import to avoid bundling axios if not used\n // eslint-disable-next-line @typescript-eslint/no-require-imports\n const axios = require('axios');\n \n const instance = axios.create({\n baseURL: config.apiBaseUrl,\n headers: {\n 'Content-Type': 'application/json',\n },\n });\n\n return createAuthClient(instance, config);\n}\n","import React, { createContext, useEffect, useState, useCallback, useMemo } from 'react';\nimport type { User, AuthState, AuthContextValue, AuthProviderProps, TokenPair, AuthConfig } from './types';\nimport {\n initTokenManager,\n getAccessToken,\n setTokens,\n clearTokens,\n isTokenExpired,\n decodeJwt,\n getValidAccessToken,\n scheduleProactiveRefresh,\n cancelProactiveRefresh,\n} from './tokenManager';\n\n// Create context with undefined default\nexport const AuthContext = createContext<AuthContextValue | undefined>(undefined);\n\n/**\n * Parse user from JWT payload\n */\nfunction parseUserFromToken(token: string): User | null {\n const payload = decodeJwt(token);\n if (!payload) return null;\n\n return {\n id: payload.sub,\n email: payload.email,\n firstName: payload.given_name,\n lastName: payload.family_name,\n displayName: payload.name,\n avatarUrl: payload.picture,\n emailVerified: payload.email_verified ?? false,\n roles: payload.roles,\n permissions: payload.permissions,\n };\n}\n\n/**\n * Build the SSO authorization URL\n */\nfunction buildAuthUrl(\n ssoBaseUrl: string,\n clientId: string,\n redirectUri: string | undefined,\n scopes: string[] = ['openid', 'email', 'profile'],\n redirectPath?: string\n): string {\n const finalRedirectUri = redirectUri || `${window.location.origin}/callback`;\n \n // Store the original path to redirect back after login\n if (redirectPath) {\n sessionStorage.setItem('arowauth_redirect_path', redirectPath);\n }\n\n const params = new URLSearchParams({\n client_id: clientId,\n redirect_uri: finalRedirectUri,\n response_type: 'token',\n scope: scopes.join(' '),\n });\n\n return `${ssoBaseUrl}/oauth/authorize?${params.toString()}`;\n}\n\n/**\n * Parse tokens from URL hash fragment (SSO callback)\n */\nfunction parseTokensFromHash(): TokenPair | null {\n if (typeof window === 'undefined') return null;\n \n const hash = window.location.hash;\n if (!hash) return null;\n\n // Parse hash fragment: #access_token=xxx&refresh_token=yyy&...\n const params = new URLSearchParams(hash.substring(1));\n \n const accessToken = params.get('access_token') || params.get('token');\n const refreshToken = params.get('refresh_token');\n\n if (accessToken && refreshToken) {\n return {\n accessToken,\n refreshToken,\n expiresIn: params.get('expires_in') ? parseInt(params.get('expires_in')!, 10) : undefined,\n tokenType: params.get('token_type') || 'Bearer',\n };\n }\n\n return null;\n}\n\n/**\n * AuthProvider component - wraps app with auth context\n */\nexport function AuthProvider(props: AuthProviderProps): React.ReactElement {\n const { children, onTokenRefresh, onAuthError, onLogout, ...config } = props;\n\n const [state, setState] = useState<AuthState>({\n user: null,\n isAuthenticated: false,\n isLoading: true,\n error: null,\n });\n\n // Initialize token manager with config\n useEffect(() => {\n const fullConfig: AuthConfig = {\n ...config,\n onTokenRefresh,\n onAuthError: (error: Error) => {\n setState((prev: AuthState) => ({ ...prev, error: error.message }));\n onAuthError?.(error);\n },\n onLogout,\n };\n initTokenManager(fullConfig);\n }, [config.ssoBaseUrl, config.clientId, config.apiBaseUrl, onTokenRefresh, onAuthError, onLogout]);\n\n // Handle SSO callback and initial auth check\n useEffect(() => {\n const startProactive = () => {\n scheduleProactiveRefresh(\n (tokens) => {\n const user = parseUserFromToken(tokens.accessToken);\n setState((prev: AuthState) => ({ ...prev, user, isAuthenticated: true, error: null }));\n onTokenRefresh?.(tokens);\n },\n () => {\n setState({ user: null, isAuthenticated: false, isLoading: false, error: null });\n },\n );\n };\n\n const initAuth = async () => {\n try {\n // Check for tokens in URL hash (SSO callback)\n const hashTokens = parseTokensFromHash();\n if (hashTokens) {\n setTokens(hashTokens.accessToken, hashTokens.refreshToken);\n \n // Clean up URL\n window.history.replaceState(null, '', window.location.pathname + window.location.search);\n \n // Redirect to original path if stored\n const redirectPath = sessionStorage.getItem('arowauth_redirect_path');\n if (redirectPath) {\n sessionStorage.removeItem('arowauth_redirect_path');\n window.history.replaceState(null, '', redirectPath);\n }\n\n onTokenRefresh?.(hashTokens);\n startProactive();\n }\n\n // Check for existing valid token\n const token = getAccessToken();\n if (token && !isTokenExpired(token)) {\n const user = parseUserFromToken(token);\n setState({\n user,\n isAuthenticated: true,\n isLoading: false,\n error: null,\n });\n startProactive();\n return;\n }\n\n // Try to refresh if we have a token but it's expired\n if (token) {\n const newToken = await getValidAccessToken();\n if (newToken) {\n const user = parseUserFromToken(newToken);\n setState({\n user,\n isAuthenticated: true,\n isLoading: false,\n error: null,\n });\n startProactive();\n return;\n }\n }\n\n // No valid auth\n setState({\n user: null,\n isAuthenticated: false,\n isLoading: false,\n error: null,\n });\n } catch (error) {\n setState({\n user: null,\n isAuthenticated: false,\n isLoading: false,\n error: error instanceof Error ? error.message : 'Authentication error',\n });\n }\n };\n\n initAuth();\n\n return () => {\n cancelProactiveRefresh();\n };\n }, [onTokenRefresh]);\n\n // Login - redirect to SSO\n const login = useCallback((redirectPath?: string) => {\n const authUrl = buildAuthUrl(\n config.ssoBaseUrl,\n config.clientId,\n config.redirectUri,\n config.scopes,\n redirectPath || window.location.pathname\n );\n window.location.href = authUrl;\n }, [config.ssoBaseUrl, config.clientId, config.redirectUri, config.scopes]);\n\n // Logout - clear tokens and optionally call SSO logout\n const logout = useCallback(async () => {\n clearTokens();\n setState({\n user: null,\n isAuthenticated: false,\n isLoading: false,\n error: null,\n });\n onLogout?.();\n }, [onLogout]);\n\n // Refresh user data from token\n const refreshUser = useCallback(async () => {\n const token = await getValidAccessToken();\n if (token) {\n const user = parseUserFromToken(token);\n setState((prev: AuthState) => ({\n ...prev,\n user,\n isAuthenticated: true,\n error: null,\n }));\n } else {\n setState({\n user: null,\n isAuthenticated: false,\n isLoading: false,\n error: null,\n });\n }\n }, []);\n\n // Memoize context value\n const contextValue = useMemo<AuthContextValue>(\n () => ({\n ...state,\n login,\n logout,\n refreshUser,\n }),\n [state, login, logout, refreshUser]\n );\n\n return (\n <AuthContext.Provider value={contextValue}>\n {children}\n </AuthContext.Provider>\n );\n}\n","import { useContext } from 'react';\nimport { AuthContext } from '../AuthProvider';\nimport type { AuthContextValue, User } from '../types';\n\n/**\n * Hook to access auth state and actions\n * \n * @returns Auth context value with user, isAuthenticated, login, logout, etc.\n * @throws Error if used outside of AuthProvider\n * \n * @example\n * ```tsx\n * function MyComponent() {\n * const { user, isAuthenticated, login, logout, isLoading } = useAuth();\n * \n * if (isLoading) return <div>Loading...</div>;\n * \n * if (!isAuthenticated) {\n * return <button onClick={() => login()}>Login</button>;\n * }\n * \n * return (\n * <div>\n * <p>Welcome, {user?.displayName || user?.email}!</p>\n * <button onClick={logout}>Logout</button>\n * </div>\n * );\n * }\n * ```\n */\nexport function useAuth(): AuthContextValue {\n const context = useContext(AuthContext);\n \n if (context === undefined) {\n throw new Error('useAuth must be used within an AuthProvider');\n }\n \n return context;\n}\n\n/**\n * Hook to check if user is authenticated (convenience wrapper)\n * \n * @returns Boolean indicating if user is authenticated\n */\nexport function useIsAuthenticated(): boolean {\n const { isAuthenticated } = useAuth();\n return isAuthenticated;\n}\n\n/**\n * Hook to get current user (convenience wrapper)\n * \n * @returns Current user or null\n */\nexport function useUser(): User | null {\n const { user } = useAuth();\n return user;\n}\n","import { useMemo, useContext } from 'react';\nimport type { AxiosInstance, InternalAxiosRequestConfig, AxiosResponse, AxiosError } from 'axios';\nimport { AuthContext } from '../AuthProvider';\nimport { getAccessToken, getValidAccessToken, clearTokens } from '../tokenManager';\n\ninterface QueuedRequest {\n resolve: (token: string | null) => void;\n reject: (error: Error) => void;\n}\n\n/**\n * Hook to get a configured axios instance with auth interceptors\n * \n * The returned axios instance will:\n * - Automatically attach Bearer token to requests\n * - Handle 401 responses by refreshing tokens and retrying\n * - Queue concurrent requests during token refresh\n * \n * @returns Configured axios instance\n * @throws Error if used outside of AuthProvider\n * \n * @example\n * ```tsx\n * function MyComponent() {\n * const client = useAuthClient();\n * \n * const fetchData = async () => {\n * try {\n * const response = await client.get('/api/data');\n * console.log(response.data);\n * } catch (error) {\n * console.error('Failed to fetch data', error);\n * }\n * };\n * \n * return <button onClick={fetchData}>Fetch Data</button>;\n * }\n * ```\n */\nexport function useAuthClient(): AxiosInstance {\n const context = useContext(AuthContext);\n \n if (context === undefined) {\n throw new Error('useAuthClient must be used within an AuthProvider');\n }\n\n const client = useMemo(() => {\n // eslint-disable-next-line @typescript-eslint/no-require-imports\n const axios = require('axios');\n \n const instance: AxiosInstance = axios.create({\n headers: {\n 'Content-Type': 'application/json',\n },\n });\n\n let isRefreshing = false;\n let requestQueue: QueuedRequest[] = [];\n\n const processQueue = (token: string | null, error: Error | null = null): void => {\n requestQueue.forEach((req) => {\n if (error) {\n req.reject(error);\n } else {\n req.resolve(token);\n }\n });\n requestQueue = [];\n };\n\n // Request interceptor\n instance.interceptors.request.use(\n async (config: InternalAxiosRequestConfig): Promise<InternalAxiosRequestConfig> => {\n if (config.url?.includes('/api/auth/refresh')) {\n return config;\n }\n const token = getAccessToken();\n if (token) {\n config.headers = config.headers || {};\n config.headers.Authorization = `Bearer ${token}`;\n }\n return config;\n },\n (error: unknown) => Promise.reject(error)\n );\n\n // Response interceptor\n instance.interceptors.response.use(\n (response: AxiosResponse) => response,\n async (error: AxiosError): Promise<AxiosResponse> => {\n const originalRequest = error.config as InternalAxiosRequestConfig & {\n _retry?: boolean;\n };\n\n if (error.response?.status !== 401 || originalRequest._retry) {\n return Promise.reject(error);\n }\n\n if (originalRequest.url?.includes('/api/auth/refresh')) {\n clearTokens();\n return Promise.reject(error);\n }\n\n if (isRefreshing) {\n return new Promise((resolve, reject) => {\n requestQueue.push({\n resolve: (token) => {\n if (token) {\n originalRequest.headers = originalRequest.headers || {};\n originalRequest.headers.Authorization = `Bearer ${token}`;\n resolve(instance(originalRequest));\n } else {\n reject(new Error('Token refresh failed'));\n }\n },\n reject,\n });\n });\n }\n\n originalRequest._retry = true;\n isRefreshing = true;\n\n try {\n const token = await getValidAccessToken();\n if (!token) {\n processQueue(null, new Error('Token refresh failed'));\n clearTokens();\n return Promise.reject(error);\n }\n\n processQueue(token);\n originalRequest.headers = originalRequest.headers || {};\n originalRequest.headers.Authorization = `Bearer ${token}`;\n return instance(originalRequest);\n } catch (refreshError) {\n processQueue(null, refreshError instanceof Error ? refreshError : new Error('Refresh failed'));\n clearTokens();\n return Promise.reject(refreshError);\n } finally {\n isRefreshing = false;\n }\n }\n );\n\n return instance;\n }, []);\n\n return client;\n}\n"]}
1
+ {"version":3,"sources":["../src/tokenManager.ts","../src/pkce.ts","../src/apiInterceptor.ts","../src/AuthProvider.tsx","../src/hooks/useAuth.ts","../src/hooks/useAuthClient.ts"],"names":["isRefreshing","config","createContext","useState","useEffect","useCallback","useMemo","useContext","requestQueue","processQueue"],"mappings":"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","file":"index.js","sourcesContent":["import type { JwtPayload, TokenPair, AuthConfig } from './types';\n\nconst DEFAULT_STORAGE_PREFIX = 'arowauth';\nconst ACCESS_TOKEN_KEY = 'access_token';\nconst REFRESH_TOKEN_KEY = 'refresh_token';\nconst TOKEN_EXPIRY_KEY = 'token_expiry';\n\n// Buffer time before expiry to trigger refresh (5 minutes for isTokenExpired checks)\nconst EXPIRY_BUFFER_SECONDS = 300;\n\n// Proactive refresh fires 30 seconds before expiry\nconst PROACTIVE_REFRESH_BUFFER_SECONDS = 30;\n\nlet config: AuthConfig | null = null;\nlet isRefreshing = false;\nlet refreshPromise: Promise<TokenPair | null> | null = null;\nlet proactiveRefreshTimer: ReturnType<typeof setTimeout> | null = null;\n\n/**\n * Initialize token manager with configuration\n */\nexport function initTokenManager(authConfig: AuthConfig): void {\n config = authConfig;\n}\n\n/**\n * Get the storage instance (localStorage or sessionStorage)\n */\nfunction getStorage(): Storage {\n if (typeof window === 'undefined') {\n // SSR fallback - return a no-op storage\n return {\n getItem: () => null,\n setItem: () => {},\n removeItem: () => {},\n clear: () => {},\n key: () => null,\n length: 0,\n };\n }\n return config?.useSessionStorage ? sessionStorage : localStorage;\n}\n\n/**\n * Get storage key with prefix\n */\nfunction getKey(key: string): string {\n const prefix = config?.storagePrefix || DEFAULT_STORAGE_PREFIX;\n return `${prefix}_${key}`;\n}\n\n/**\n * Decode a JWT token without verification\n */\nexport function decodeJwt(token: string): JwtPayload | null {\n try {\n const parts = token.split('.');\n if (parts.length !== 3) return null;\n \n const payload = parts[1];\n // Handle URL-safe base64\n const base64 = payload.replace(/-/g, '+').replace(/_/g, '/');\n const jsonPayload = decodeURIComponent(\n atob(base64)\n .split('')\n .map((c) => '%' + ('00' + c.charCodeAt(0).toString(16)).slice(-2))\n .join('')\n );\n \n return JSON.parse(jsonPayload) as JwtPayload;\n } catch {\n return null;\n }\n}\n\n/**\n * Get the access token from storage\n */\nexport function getAccessToken(): string | null {\n return getStorage().getItem(getKey(ACCESS_TOKEN_KEY));\n}\n\n/**\n * Get the refresh token from storage\n */\nexport function getRefreshToken(): string | null {\n return getStorage().getItem(getKey(REFRESH_TOKEN_KEY));\n}\n\n/**\n * Get the stored token expiry timestamp (seconds since epoch)\n */\nexport function getTokenExpiry(): number | null {\n const expiry = getStorage().getItem(getKey(TOKEN_EXPIRY_KEY));\n return expiry ? parseInt(expiry, 10) : null;\n}\n\n/**\n * Store tokens in storage, including the expiry timestamp decoded from the JWT\n */\nexport function setTokens(accessToken: string, refreshToken: string): void {\n const storage = getStorage();\n storage.setItem(getKey(ACCESS_TOKEN_KEY), accessToken);\n storage.setItem(getKey(REFRESH_TOKEN_KEY), refreshToken);\n\n // Persist expiry from JWT exp claim\n const payload = decodeJwt(accessToken);\n if (payload?.exp) {\n storage.setItem(getKey(TOKEN_EXPIRY_KEY), String(payload.exp));\n }\n}\n\n/**\n * Clear all tokens from storage\n */\nexport function clearTokens(): void {\n const storage = getStorage();\n storage.removeItem(getKey(ACCESS_TOKEN_KEY));\n storage.removeItem(getKey(REFRESH_TOKEN_KEY));\n storage.removeItem(getKey(TOKEN_EXPIRY_KEY));\n cancelProactiveRefresh();\n}\n\n/**\n * Check if the access token is expired or about to expire\n */\nexport function isTokenExpired(token?: string | null): boolean {\n const accessToken = token ?? getAccessToken();\n if (!accessToken) return true;\n \n const payload = decodeJwt(accessToken);\n if (!payload || !payload.exp) return true;\n \n // Check if token expires within buffer period\n const now = Math.floor(Date.now() / 1000);\n return payload.exp <= now + EXPIRY_BUFFER_SECONDS;\n}\n\n/**\n * Check if we have a valid (non-expired) access token\n */\nexport function hasValidToken(): boolean {\n const token = getAccessToken();\n return token !== null && !isTokenExpired(token);\n}\n\n/**\n * Get user info from the current access token\n */\nexport function getUserFromToken(): JwtPayload | null {\n const token = getAccessToken();\n if (!token) return null;\n return decodeJwt(token);\n}\n\n/**\n * Refresh tokens using the refresh token\n * Handles concurrent refresh requests by returning the same promise\n */\nexport async function refreshTokens(): Promise<TokenPair | null> {\n if (!config) {\n throw new Error('TokenManager not initialized. Call initTokenManager first.');\n }\n\n const refreshToken = getRefreshToken();\n if (!refreshToken) {\n clearTokens();\n return null;\n }\n\n // If already refreshing, return the existing promise\n if (isRefreshing && refreshPromise) {\n return refreshPromise;\n }\n\n isRefreshing = true;\n refreshPromise = performRefresh(refreshToken);\n\n try {\n const result = await refreshPromise;\n return result;\n } finally {\n isRefreshing = false;\n refreshPromise = null;\n }\n}\n\n/**\n * Perform the actual token refresh request\n */\nasync function performRefresh(refreshToken: string): Promise<TokenPair | null> {\n if (!config) return null;\n\n try {\n const response = await fetch(`${(config.ssoApiUrl || config.ssoBaseUrl)}/api/auth/refresh`, {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json',\n },\n body: JSON.stringify({ refreshToken }),\n });\n\n if (!response.ok) {\n clearTokens();\n config.onAuthError?.(new Error('Token refresh failed'));\n return null;\n }\n\n const data = await response.json();\n const tokens: TokenPair = {\n accessToken: data.accessToken || data.access_token,\n refreshToken: data.refreshToken || data.refresh_token,\n expiresIn: data.expiresIn || data.expires_in,\n tokenType: data.tokenType || data.token_type || 'Bearer',\n };\n\n setTokens(tokens.accessToken, tokens.refreshToken);\n config.onTokenRefresh?.(tokens);\n\n return tokens;\n } catch (error) {\n clearTokens();\n config.onAuthError?.(error instanceof Error ? error : new Error('Token refresh failed'));\n return null;\n }\n}\n\n/**\n * Get a valid access token, refreshing if necessary\n */\nexport async function getValidAccessToken(): Promise<string | null> {\n const token = getAccessToken();\n \n if (token && !isTokenExpired(token)) {\n return token;\n }\n\n const refreshed = await refreshTokens();\n return refreshed?.accessToken ?? null;\n}\n\n/**\n * Cancel any pending proactive refresh timer\n */\nexport function cancelProactiveRefresh(): void {\n if (proactiveRefreshTimer !== null) {\n clearTimeout(proactiveRefreshTimer);\n proactiveRefreshTimer = null;\n }\n}\n\n/**\n * Schedule a proactive token refresh ~30 seconds before expiry.\n * Calls `onRefreshed` with the new token pair on success so the\n * AuthProvider can update React state without a re-mount.\n */\nexport function scheduleProactiveRefresh(\n onRefreshed?: (tokens: TokenPair) => void,\n onFailed?: () => void,\n): void {\n cancelProactiveRefresh();\n\n const expiry = getTokenExpiry();\n if (!expiry) return;\n\n const now = Math.floor(Date.now() / 1000);\n const delaySeconds = expiry - now - PROACTIVE_REFRESH_BUFFER_SECONDS;\n\n // If already past the proactive window, don't schedule (the normal\n // isTokenExpired / 401 fallback will handle it)\n if (delaySeconds <= 0) return;\n\n proactiveRefreshTimer = setTimeout(async () => {\n proactiveRefreshTimer = null;\n const tokens = await refreshTokens();\n if (tokens) {\n // Re-schedule for the next cycle\n scheduleProactiveRefresh(onRefreshed, onFailed);\n onRefreshed?.(tokens);\n } else {\n onFailed?.();\n }\n }, delaySeconds * 1000);\n}\n","/**\n * PKCE (Proof Key for Code Exchange) helper functions for OAuth 2.0 Authorization Code Flow\n * \n * RFC 7636: https://datatracker.ietf.org/doc/html/rfc7636\n */\n\n/**\n * Generate a cryptographically random code verifier\n * Returns a base64url-encoded string of 32 random bytes (43 characters)\n */\nexport function generateCodeVerifier(): string {\n const array = new Uint8Array(32);\n crypto.getRandomValues(array);\n return base64UrlEncode(array);\n}\n\n/**\n * Generate a code challenge from a code verifier using SHA-256\n * @param verifier - The code verifier string\n * @returns Promise resolving to the base64url-encoded SHA-256 hash\n */\nexport async function generateCodeChallenge(verifier: string): Promise<string> {\n const encoder = new TextEncoder();\n const data = encoder.encode(verifier);\n const hash = await crypto.subtle.digest('SHA-256', data);\n return base64UrlEncode(new Uint8Array(hash));\n}\n\n/**\n * Encode a byte array to base64url format (RFC 4648 Section 5)\n * @param bytes - The byte array to encode\n * @returns Base64url-encoded string\n */\nfunction base64UrlEncode(bytes: Uint8Array): string {\n let str = '';\n bytes.forEach(b => str += String.fromCharCode(b));\n return btoa(str)\n .replace(/\\+/g, '-')\n .replace(/\\//g, '_')\n .replace(/=+$/, '');\n}\n","import type { AxiosInstance, InternalAxiosRequestConfig, AxiosResponse, AxiosError } from 'axios';\nimport { getAccessToken, getValidAccessToken, clearTokens } from './tokenManager';\nimport type { AuthConfig } from './types';\n\ninterface QueuedRequest {\n resolve: (token: string | null) => void;\n reject: (error: Error) => void;\n}\n\nlet isRefreshing = false;\nlet requestQueue: QueuedRequest[] = [];\n\n/**\n * Process queued requests after token refresh\n */\nfunction processQueue(token: string | null, error: Error | null = null): void {\n requestQueue.forEach((request) => {\n if (error) {\n request.reject(error);\n } else {\n request.resolve(token);\n }\n });\n requestQueue = [];\n}\n\n/**\n * Create and configure axios instance with auth interceptors\n */\nexport function createAuthClient(\n axiosInstance: AxiosInstance,\n config: AuthConfig\n): AxiosInstance {\n // Request interceptor - attach Bearer token\n axiosInstance.interceptors.request.use(\n async (requestConfig: InternalAxiosRequestConfig): Promise<InternalAxiosRequestConfig> => {\n // Skip auth for refresh endpoint to avoid infinite loop\n if (requestConfig.url?.includes('/api/auth/refresh')) {\n return requestConfig;\n }\n\n const token = getAccessToken();\n if (token) {\n requestConfig.headers = requestConfig.headers || {};\n requestConfig.headers.Authorization = `Bearer ${token}`;\n }\n return requestConfig;\n },\n (error: unknown) => Promise.reject(error)\n );\n\n // Response interceptor - handle 401 and refresh token\n axiosInstance.interceptors.response.use(\n (response: AxiosResponse) => response,\n async (error: AxiosError): Promise<AxiosResponse> => {\n const originalRequest = error.config as InternalAxiosRequestConfig & {\n _retry?: boolean;\n };\n\n // Only handle 401 errors\n if (error.response?.status !== 401) {\n return Promise.reject(error);\n }\n\n // Don't retry if already retried or no config\n if (originalRequest._retry || !originalRequest) {\n clearTokens();\n config.onAuthError?.(new Error('Authentication failed'));\n return Promise.reject(error);\n }\n\n // Don't retry refresh endpoint\n if (originalRequest.url?.includes('/api/auth/refresh')) {\n clearTokens();\n config.onAuthError?.(new Error('Token refresh failed'));\n return Promise.reject(error);\n }\n\n // If already refreshing, queue this request\n if (isRefreshing) {\n return new Promise((resolve, reject) => {\n requestQueue.push({\n resolve: (token) => {\n if (token) {\n originalRequest.headers = originalRequest.headers || {};\n originalRequest.headers.Authorization = `Bearer ${token}`;\n resolve(axiosInstance(originalRequest));\n } else {\n reject(new Error('Token refresh failed'));\n }\n },\n reject,\n });\n });\n }\n\n originalRequest._retry = true;\n isRefreshing = true;\n\n try {\n const token = await getValidAccessToken();\n \n if (!token) {\n processQueue(null, new Error('Token refresh failed'));\n clearTokens();\n config.onAuthError?.(new Error('Token refresh failed'));\n return Promise.reject(error);\n }\n\n processQueue(token);\n \n originalRequest.headers = originalRequest.headers || {};\n originalRequest.headers.Authorization = `Bearer ${token}`;\n \n return axiosInstance(originalRequest);\n } catch (refreshError) {\n processQueue(null, refreshError instanceof Error ? refreshError : new Error('Token refresh failed'));\n clearTokens();\n config.onAuthError?.(refreshError instanceof Error ? refreshError : new Error('Token refresh failed'));\n return Promise.reject(refreshError);\n } finally {\n isRefreshing = false;\n }\n }\n );\n\n return axiosInstance;\n}\n\n/**\n * Create a new axios instance with auth interceptors\n */\nexport function createApiClient(config: AuthConfig): AxiosInstance {\n // Dynamic import to avoid bundling axios if not used\n // eslint-disable-next-line @typescript-eslint/no-require-imports\n const axios = require('axios');\n \n const instance = axios.create({\n baseURL: config.apiBaseUrl,\n headers: {\n 'Content-Type': 'application/json',\n },\n });\n\n return createAuthClient(instance, config);\n}\n","import React, { createContext, useEffect, useState, useCallback, useMemo } from 'react';\nimport type { User, AuthState, AuthContextValue, AuthProviderProps, TokenPair, AuthConfig } from './types';\nimport {\n initTokenManager,\n getAccessToken,\n setTokens,\n clearTokens,\n isTokenExpired,\n decodeJwt,\n getValidAccessToken,\n scheduleProactiveRefresh,\n cancelProactiveRefresh,\n} from './tokenManager';\nimport { generateCodeVerifier, generateCodeChallenge } from './pkce';\n\n// Create context with undefined default\nexport const AuthContext = createContext<AuthContextValue | undefined>(undefined);\n\n/**\n * Parse user from JWT payload\n */\nfunction parseUserFromToken(token: string): User | null {\n const payload = decodeJwt(token);\n if (!payload) return null;\n\n return {\n id: payload.sub,\n email: payload.email,\n firstName: payload.given_name,\n lastName: payload.family_name,\n displayName: payload.name,\n avatarUrl: payload.picture,\n emailVerified: payload.email_verified ?? false,\n roles: payload.roles,\n permissions: payload.permissions,\n };\n}\n\n/**\n * Build the SSO authorization URL with PKCE\n */\nasync function buildAuthUrl(\n ssoBaseUrl: string,\n clientId: string,\n redirectUri: string | undefined,\n scopes: string[] = ['openid', 'email', 'profile'],\n redirectPath?: string\n): Promise<string> {\n const finalRedirectUri = redirectUri || `${window.location.origin}/callback`;\n \n // Store the original path to redirect back after login\n if (redirectPath) {\n sessionStorage.setItem('arowauth_redirect_path', redirectPath);\n }\n\n // Generate PKCE parameters\n const codeVerifier = generateCodeVerifier();\n const codeChallenge = await generateCodeChallenge(codeVerifier);\n \n // Store code verifier for later use in token exchange\n sessionStorage.setItem('arow_pkce_code_verifier', codeVerifier);\n\n const params = new URLSearchParams({\n client_id: clientId,\n redirect_uri: finalRedirectUri,\n response_type: 'code',\n scope: scopes.join(' '),\n code_challenge: codeChallenge,\n code_challenge_method: 'S256',\n });\n\n return `${ssoBaseUrl}/oauth/authorize?${params.toString()}`;\n}\n\n/**\n * Parse authorization code from URL query params (PKCE callback)\n */\nfunction parseCodeFromQuery(): { code: string; state?: string } | null {\n if (typeof window === 'undefined') return null;\n \n const params = new URLSearchParams(window.location.search);\n const code = params.get('code');\n \n if (!code) return null;\n \n return {\n code,\n state: params.get('state') || undefined,\n };\n}\n\n/**\n * Exchange authorization code for tokens using PKCE\n */\nasync function exchangeCodeForTokens(\n ssoApiUrl: string,\n clientId: string,\n redirectUri: string,\n code: string\n): Promise<TokenPair | null> {\n try {\n // Retrieve and remove code verifier from session storage\n const codeVerifier = sessionStorage.getItem('arow_pkce_code_verifier');\n if (!codeVerifier) {\n throw new Error('Code verifier not found in session storage');\n }\n sessionStorage.removeItem('arow_pkce_code_verifier');\n\n // Build the token exchange request body\n const body = new URLSearchParams({\n grant_type: 'authorization_code',\n code,\n client_id: clientId,\n redirect_uri: redirectUri,\n code_verifier: codeVerifier,\n });\n\n const response = await fetch(`${ssoApiUrl}/oauth/token`, {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/x-www-form-urlencoded',\n },\n body: body.toString(),\n });\n\n if (!response.ok) {\n throw new Error(`Token exchange failed: ${response.status} ${response.statusText}`);\n }\n\n const data = await response.json();\n \n return {\n accessToken: data.access_token || data.accessToken,\n refreshToken: data.refresh_token || data.refreshToken,\n expiresIn: data.expires_in || data.expiresIn,\n tokenType: data.token_type || data.tokenType || 'Bearer',\n };\n } catch (error) {\n console.error('Failed to exchange code for tokens:', error);\n return null;\n }\n}\n\n/**\n * Parse tokens from URL hash fragment (SSO callback - DEPRECATED, v1 backward compatibility)\n */\nfunction parseTokensFromHash(): TokenPair | null {\n if (typeof window === 'undefined') return null;\n \n const hash = window.location.hash;\n if (!hash) return null;\n\n // Parse hash fragment: #access_token=xxx&refresh_token=yyy&...\n const params = new URLSearchParams(hash.substring(1));\n \n const accessToken = params.get('access_token') || params.get('token');\n const refreshToken = params.get('refresh_token');\n\n if (accessToken && refreshToken) {\n return {\n accessToken,\n refreshToken,\n expiresIn: params.get('expires_in') ? parseInt(params.get('expires_in')!, 10) : undefined,\n tokenType: params.get('token_type') || 'Bearer',\n };\n }\n\n return null;\n}\n\n/**\n * AuthProvider component - wraps app with auth context\n */\nexport function AuthProvider(props: AuthProviderProps): React.ReactElement {\n const { children, onTokenRefresh, onAuthError, onLogout, ...config } = props;\n\n const [state, setState] = useState<AuthState>({\n user: null,\n isAuthenticated: false,\n isLoading: true,\n error: null,\n });\n\n // Initialize token manager with config\n useEffect(() => {\n const fullConfig: AuthConfig = {\n ...config,\n onTokenRefresh,\n onAuthError: (error: Error) => {\n setState((prev: AuthState) => ({ ...prev, error: error.message }));\n onAuthError?.(error);\n },\n onLogout,\n };\n initTokenManager(fullConfig);\n }, [config.ssoBaseUrl, config.ssoApiUrl, config.clientId, config.apiBaseUrl, onTokenRefresh, onAuthError, onLogout]);\n\n // Handle SSO callback and initial auth check\n useEffect(() => {\n const startProactive = () => {\n scheduleProactiveRefresh(\n (tokens) => {\n const user = parseUserFromToken(tokens.accessToken);\n setState((prev: AuthState) => ({ ...prev, user, isAuthenticated: true, error: null }));\n onTokenRefresh?.(tokens);\n },\n () => {\n setState({ user: null, isAuthenticated: false, isLoading: false, error: null });\n },\n );\n };\n\n const initAuth = async () => {\n try {\n // PRIORITY 1: Check for authorization code in query params (PKCE v2 flow)\n const codeData = parseCodeFromQuery();\n if (codeData) {\n const finalRedirectUri = config.redirectUri || `${window.location.origin}/callback`;\n const tokens = await exchangeCodeForTokens(\n config.ssoApiUrl || config.ssoBaseUrl,\n config.clientId,\n finalRedirectUri,\n codeData.code\n );\n \n if (tokens) {\n setTokens(tokens.accessToken, tokens.refreshToken);\n \n // Clean up URL - remove query params\n const cleanUrl = window.location.pathname;\n window.history.replaceState(null, '', cleanUrl);\n \n // Redirect to original path if stored\n const redirectPath = sessionStorage.getItem('arowauth_redirect_path');\n if (redirectPath) {\n sessionStorage.removeItem('arowauth_redirect_path');\n window.history.replaceState(null, '', redirectPath);\n }\n\n onTokenRefresh?.(tokens);\n startProactive();\n \n const user = parseUserFromToken(tokens.accessToken);\n setState({\n user,\n isAuthenticated: true,\n isLoading: false,\n error: null,\n });\n return;\n } else {\n // Code exchange failed\n setState({\n user: null,\n isAuthenticated: false,\n isLoading: false,\n error: 'Failed to exchange authorization code for tokens',\n });\n return;\n }\n }\n\n // PRIORITY 2: Check for tokens in URL hash (v1 implicit flow - backward compatibility)\n const hashTokens = parseTokensFromHash();\n if (hashTokens) {\n setTokens(hashTokens.accessToken, hashTokens.refreshToken);\n \n // Clean up URL\n window.history.replaceState(null, '', window.location.pathname + window.location.search);\n \n // Redirect to original path if stored\n const redirectPath = sessionStorage.getItem('arowauth_redirect_path');\n if (redirectPath) {\n sessionStorage.removeItem('arowauth_redirect_path');\n window.history.replaceState(null, '', redirectPath);\n }\n\n onTokenRefresh?.(hashTokens);\n startProactive();\n }\n\n // Check for existing valid token\n const token = getAccessToken();\n if (token && !isTokenExpired(token)) {\n const user = parseUserFromToken(token);\n setState({\n user,\n isAuthenticated: true,\n isLoading: false,\n error: null,\n });\n startProactive();\n return;\n }\n\n // Try to refresh if we have a token but it's expired\n if (token) {\n const newToken = await getValidAccessToken();\n if (newToken) {\n const user = parseUserFromToken(newToken);\n setState({\n user,\n isAuthenticated: true,\n isLoading: false,\n error: null,\n });\n startProactive();\n return;\n }\n }\n\n // No valid auth\n setState({\n user: null,\n isAuthenticated: false,\n isLoading: false,\n error: null,\n });\n } catch (error) {\n setState({\n user: null,\n isAuthenticated: false,\n isLoading: false,\n error: error instanceof Error ? error.message : 'Authentication error',\n });\n }\n };\n\n initAuth();\n\n return () => {\n cancelProactiveRefresh();\n };\n }, [onTokenRefresh]);\n\n // Login - redirect to SSO\n const login = useCallback(async (redirectPath?: string) => {\n const authUrl = await buildAuthUrl(\n config.ssoBaseUrl,\n config.clientId,\n config.redirectUri,\n config.scopes,\n redirectPath || window.location.pathname\n );\n window.location.href = authUrl;\n }, [config.ssoBaseUrl, config.clientId, config.redirectUri, config.scopes]);\n\n // Logout - clear tokens and optionally call SSO logout\n const logout = useCallback(async () => {\n clearTokens();\n setState({\n user: null,\n isAuthenticated: false,\n isLoading: false,\n error: null,\n });\n onLogout?.();\n }, [onLogout]);\n\n // Refresh user data from token\n const refreshUser = useCallback(async () => {\n const token = await getValidAccessToken();\n if (token) {\n const user = parseUserFromToken(token);\n setState((prev: AuthState) => ({\n ...prev,\n user,\n isAuthenticated: true,\n error: null,\n }));\n } else {\n setState({\n user: null,\n isAuthenticated: false,\n isLoading: false,\n error: null,\n });\n }\n }, []);\n\n // Memoize context value\n const contextValue = useMemo<AuthContextValue>(\n () => ({\n ...state,\n login,\n logout,\n refreshUser,\n }),\n [state, login, logout, refreshUser]\n );\n\n return (\n <AuthContext.Provider value={contextValue}>\n {children}\n </AuthContext.Provider>\n );\n}\n","import { useContext } from 'react';\nimport { AuthContext } from '../AuthProvider';\nimport type { AuthContextValue, User } from '../types';\n\n/**\n * Hook to access auth state and actions\n * \n * @returns Auth context value with user, isAuthenticated, login, logout, etc.\n * @throws Error if used outside of AuthProvider\n * \n * @example\n * ```tsx\n * function MyComponent() {\n * const { user, isAuthenticated, login, logout, isLoading } = useAuth();\n * \n * if (isLoading) return <div>Loading...</div>;\n * \n * if (!isAuthenticated) {\n * return <button onClick={() => login()}>Login</button>;\n * }\n * \n * return (\n * <div>\n * <p>Welcome, {user?.displayName || user?.email}!</p>\n * <button onClick={logout}>Logout</button>\n * </div>\n * );\n * }\n * ```\n */\nexport function useAuth(): AuthContextValue {\n const context = useContext(AuthContext);\n \n if (context === undefined) {\n throw new Error('useAuth must be used within an AuthProvider');\n }\n \n return context;\n}\n\n/**\n * Hook to check if user is authenticated (convenience wrapper)\n * \n * @returns Boolean indicating if user is authenticated\n */\nexport function useIsAuthenticated(): boolean {\n const { isAuthenticated } = useAuth();\n return isAuthenticated;\n}\n\n/**\n * Hook to get current user (convenience wrapper)\n * \n * @returns Current user or null\n */\nexport function useUser(): User | null {\n const { user } = useAuth();\n return user;\n}\n","import { useMemo, useContext } from 'react';\nimport type { AxiosInstance, InternalAxiosRequestConfig, AxiosResponse, AxiosError } from 'axios';\nimport { AuthContext } from '../AuthProvider';\nimport { getAccessToken, getValidAccessToken, clearTokens } from '../tokenManager';\n\ninterface QueuedRequest {\n resolve: (token: string | null) => void;\n reject: (error: Error) => void;\n}\n\n/**\n * Hook to get a configured axios instance with auth interceptors\n * \n * The returned axios instance will:\n * - Automatically attach Bearer token to requests\n * - Handle 401 responses by refreshing tokens and retrying\n * - Queue concurrent requests during token refresh\n * \n * @returns Configured axios instance\n * @throws Error if used outside of AuthProvider\n * \n * @example\n * ```tsx\n * function MyComponent() {\n * const client = useAuthClient();\n * \n * const fetchData = async () => {\n * try {\n * const response = await client.get('/api/data');\n * console.log(response.data);\n * } catch (error) {\n * console.error('Failed to fetch data', error);\n * }\n * };\n * \n * return <button onClick={fetchData}>Fetch Data</button>;\n * }\n * ```\n */\nexport function useAuthClient(): AxiosInstance {\n const context = useContext(AuthContext);\n \n if (context === undefined) {\n throw new Error('useAuthClient must be used within an AuthProvider');\n }\n\n const client = useMemo(() => {\n // eslint-disable-next-line @typescript-eslint/no-require-imports\n const axios = require('axios');\n \n const instance: AxiosInstance = axios.create({\n headers: {\n 'Content-Type': 'application/json',\n },\n });\n\n let isRefreshing = false;\n let requestQueue: QueuedRequest[] = [];\n\n const processQueue = (token: string | null, error: Error | null = null): void => {\n requestQueue.forEach((req) => {\n if (error) {\n req.reject(error);\n } else {\n req.resolve(token);\n }\n });\n requestQueue = [];\n };\n\n // Request interceptor\n instance.interceptors.request.use(\n async (config: InternalAxiosRequestConfig): Promise<InternalAxiosRequestConfig> => {\n if (config.url?.includes('/api/auth/refresh')) {\n return config;\n }\n const token = getAccessToken();\n if (token) {\n config.headers = config.headers || {};\n config.headers.Authorization = `Bearer ${token}`;\n }\n return config;\n },\n (error: unknown) => Promise.reject(error)\n );\n\n // Response interceptor\n instance.interceptors.response.use(\n (response: AxiosResponse) => response,\n async (error: AxiosError): Promise<AxiosResponse> => {\n const originalRequest = error.config as InternalAxiosRequestConfig & {\n _retry?: boolean;\n };\n\n if (error.response?.status !== 401 || originalRequest._retry) {\n return Promise.reject(error);\n }\n\n if (originalRequest.url?.includes('/api/auth/refresh')) {\n clearTokens();\n return Promise.reject(error);\n }\n\n if (isRefreshing) {\n return new Promise((resolve, reject) => {\n requestQueue.push({\n resolve: (token) => {\n if (token) {\n originalRequest.headers = originalRequest.headers || {};\n originalRequest.headers.Authorization = `Bearer ${token}`;\n resolve(instance(originalRequest));\n } else {\n reject(new Error('Token refresh failed'));\n }\n },\n reject,\n });\n });\n }\n\n originalRequest._retry = true;\n isRefreshing = true;\n\n try {\n const token = await getValidAccessToken();\n if (!token) {\n processQueue(null, new Error('Token refresh failed'));\n clearTokens();\n return Promise.reject(error);\n }\n\n processQueue(token);\n originalRequest.headers = originalRequest.headers || {};\n originalRequest.headers.Authorization = `Bearer ${token}`;\n return instance(originalRequest);\n } catch (refreshError) {\n processQueue(null, refreshError instanceof Error ? refreshError : new Error('Refresh failed'));\n clearTokens();\n return Promise.reject(refreshError);\n } finally {\n isRefreshing = false;\n }\n }\n );\n\n return instance;\n }, []);\n\n return client;\n}\n"]}
package/dist/index.mjs CHANGED
@@ -124,7 +124,7 @@ async function refreshTokens() {
124
124
  async function performRefresh(refreshToken) {
125
125
  if (!config) return null;
126
126
  try {
127
- const response = await fetch(`${config.ssoBaseUrl}/api/auth/refresh`, {
127
+ const response = await fetch(`${config.ssoApiUrl || config.ssoBaseUrl}/api/auth/refresh`, {
128
128
  method: "POST",
129
129
  headers: {
130
130
  "Content-Type": "application/json"
@@ -185,6 +185,24 @@ function scheduleProactiveRefresh(onRefreshed, onFailed) {
185
185
  }, delaySeconds * 1e3);
186
186
  }
187
187
 
188
+ // src/pkce.ts
189
+ function generateCodeVerifier() {
190
+ const array = new Uint8Array(32);
191
+ crypto.getRandomValues(array);
192
+ return base64UrlEncode(array);
193
+ }
194
+ async function generateCodeChallenge(verifier) {
195
+ const encoder = new TextEncoder();
196
+ const data = encoder.encode(verifier);
197
+ const hash = await crypto.subtle.digest("SHA-256", data);
198
+ return base64UrlEncode(new Uint8Array(hash));
199
+ }
200
+ function base64UrlEncode(bytes) {
201
+ let str = "";
202
+ bytes.forEach((b) => str += String.fromCharCode(b));
203
+ return btoa(str).replace(/\+/g, "-").replace(/\//g, "_").replace(/=+$/, "");
204
+ }
205
+
188
206
  // src/apiInterceptor.ts
189
207
  var isRefreshing2 = false;
190
208
  var requestQueue = [];
@@ -298,19 +316,70 @@ function parseUserFromToken(token) {
298
316
  permissions: payload.permissions
299
317
  };
300
318
  }
301
- function buildAuthUrl(ssoBaseUrl, clientId, redirectUri, scopes = ["openid", "email", "profile"], redirectPath) {
319
+ async function buildAuthUrl(ssoBaseUrl, clientId, redirectUri, scopes = ["openid", "email", "profile"], redirectPath) {
302
320
  const finalRedirectUri = redirectUri || `${window.location.origin}/callback`;
303
321
  if (redirectPath) {
304
322
  sessionStorage.setItem("arowauth_redirect_path", redirectPath);
305
323
  }
324
+ const codeVerifier = generateCodeVerifier();
325
+ const codeChallenge = await generateCodeChallenge(codeVerifier);
326
+ sessionStorage.setItem("arow_pkce_code_verifier", codeVerifier);
306
327
  const params = new URLSearchParams({
307
328
  client_id: clientId,
308
329
  redirect_uri: finalRedirectUri,
309
- response_type: "token",
310
- scope: scopes.join(" ")
330
+ response_type: "code",
331
+ scope: scopes.join(" "),
332
+ code_challenge: codeChallenge,
333
+ code_challenge_method: "S256"
311
334
  });
312
335
  return `${ssoBaseUrl}/oauth/authorize?${params.toString()}`;
313
336
  }
337
+ function parseCodeFromQuery() {
338
+ if (typeof window === "undefined") return null;
339
+ const params = new URLSearchParams(window.location.search);
340
+ const code = params.get("code");
341
+ if (!code) return null;
342
+ return {
343
+ code,
344
+ state: params.get("state") || void 0
345
+ };
346
+ }
347
+ async function exchangeCodeForTokens(ssoApiUrl, clientId, redirectUri, code) {
348
+ try {
349
+ const codeVerifier = sessionStorage.getItem("arow_pkce_code_verifier");
350
+ if (!codeVerifier) {
351
+ throw new Error("Code verifier not found in session storage");
352
+ }
353
+ sessionStorage.removeItem("arow_pkce_code_verifier");
354
+ const body = new URLSearchParams({
355
+ grant_type: "authorization_code",
356
+ code,
357
+ client_id: clientId,
358
+ redirect_uri: redirectUri,
359
+ code_verifier: codeVerifier
360
+ });
361
+ const response = await fetch(`${ssoApiUrl}/oauth/token`, {
362
+ method: "POST",
363
+ headers: {
364
+ "Content-Type": "application/x-www-form-urlencoded"
365
+ },
366
+ body: body.toString()
367
+ });
368
+ if (!response.ok) {
369
+ throw new Error(`Token exchange failed: ${response.status} ${response.statusText}`);
370
+ }
371
+ const data = await response.json();
372
+ return {
373
+ accessToken: data.access_token || data.accessToken,
374
+ refreshToken: data.refresh_token || data.refreshToken,
375
+ expiresIn: data.expires_in || data.expiresIn,
376
+ tokenType: data.token_type || data.tokenType || "Bearer"
377
+ };
378
+ } catch (error) {
379
+ console.error("Failed to exchange code for tokens:", error);
380
+ return null;
381
+ }
382
+ }
314
383
  function parseTokensFromHash() {
315
384
  if (typeof window === "undefined") return null;
316
385
  const hash = window.location.hash;
@@ -347,7 +416,7 @@ function AuthProvider(props) {
347
416
  onLogout
348
417
  };
349
418
  initTokenManager(fullConfig);
350
- }, [config2.ssoBaseUrl, config2.clientId, config2.apiBaseUrl, onTokenRefresh, onAuthError, onLogout]);
419
+ }, [config2.ssoBaseUrl, config2.ssoApiUrl, config2.clientId, config2.apiBaseUrl, onTokenRefresh, onAuthError, onLogout]);
351
420
  useEffect(() => {
352
421
  const startProactive = () => {
353
422
  scheduleProactiveRefresh(
@@ -363,6 +432,44 @@ function AuthProvider(props) {
363
432
  };
364
433
  const initAuth = async () => {
365
434
  try {
435
+ const codeData = parseCodeFromQuery();
436
+ if (codeData) {
437
+ const finalRedirectUri = config2.redirectUri || `${window.location.origin}/callback`;
438
+ const tokens = await exchangeCodeForTokens(
439
+ config2.ssoApiUrl || config2.ssoBaseUrl,
440
+ config2.clientId,
441
+ finalRedirectUri,
442
+ codeData.code
443
+ );
444
+ if (tokens) {
445
+ setTokens(tokens.accessToken, tokens.refreshToken);
446
+ const cleanUrl = window.location.pathname;
447
+ window.history.replaceState(null, "", cleanUrl);
448
+ const redirectPath = sessionStorage.getItem("arowauth_redirect_path");
449
+ if (redirectPath) {
450
+ sessionStorage.removeItem("arowauth_redirect_path");
451
+ window.history.replaceState(null, "", redirectPath);
452
+ }
453
+ onTokenRefresh?.(tokens);
454
+ startProactive();
455
+ const user = parseUserFromToken(tokens.accessToken);
456
+ setState({
457
+ user,
458
+ isAuthenticated: true,
459
+ isLoading: false,
460
+ error: null
461
+ });
462
+ return;
463
+ } else {
464
+ setState({
465
+ user: null,
466
+ isAuthenticated: false,
467
+ isLoading: false,
468
+ error: "Failed to exchange authorization code for tokens"
469
+ });
470
+ return;
471
+ }
472
+ }
366
473
  const hashTokens = parseTokensFromHash();
367
474
  if (hashTokens) {
368
475
  setTokens(hashTokens.accessToken, hashTokens.refreshToken);
@@ -421,8 +528,8 @@ function AuthProvider(props) {
421
528
  cancelProactiveRefresh();
422
529
  };
423
530
  }, [onTokenRefresh]);
424
- const login = useCallback((redirectPath) => {
425
- const authUrl = buildAuthUrl(
531
+ const login = useCallback(async (redirectPath) => {
532
+ const authUrl = await buildAuthUrl(
426
533
  config2.ssoBaseUrl,
427
534
  config2.clientId,
428
535
  config2.redirectUri,
@@ -578,6 +685,6 @@ function useAuthClient() {
578
685
  return client;
579
686
  }
580
687
 
581
- export { AuthContext, AuthProvider, cancelProactiveRefresh, clearTokens, createApiClient, createAuthClient, decodeJwt, getAccessToken, getRefreshToken, getTokenExpiry, getUserFromToken, getValidAccessToken, hasValidToken, initTokenManager, isTokenExpired, refreshTokens, scheduleProactiveRefresh, setTokens, useAuth, useAuthClient, useIsAuthenticated, useUser };
688
+ export { AuthContext, AuthProvider, cancelProactiveRefresh, clearTokens, createApiClient, createAuthClient, decodeJwt, generateCodeChallenge, generateCodeVerifier, getAccessToken, getRefreshToken, getTokenExpiry, getUserFromToken, getValidAccessToken, hasValidToken, initTokenManager, isTokenExpired, refreshTokens, scheduleProactiveRefresh, setTokens, useAuth, useAuthClient, useIsAuthenticated, useUser };
582
689
  //# sourceMappingURL=index.mjs.map
583
690
  //# sourceMappingURL=index.mjs.map
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/tokenManager.ts","../src/apiInterceptor.ts","../src/AuthProvider.tsx","../src/hooks/useAuth.ts","../src/hooks/useAuthClient.ts"],"names":["isRefreshing","config","useContext","useMemo","requestQueue","processQueue"],"mappings":"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","file":"index.mjs","sourcesContent":["import type { JwtPayload, TokenPair, AuthConfig } from './types';\n\nconst DEFAULT_STORAGE_PREFIX = 'arowauth';\nconst ACCESS_TOKEN_KEY = 'access_token';\nconst REFRESH_TOKEN_KEY = 'refresh_token';\nconst TOKEN_EXPIRY_KEY = 'token_expiry';\n\n// Buffer time before expiry to trigger refresh (5 minutes for isTokenExpired checks)\nconst EXPIRY_BUFFER_SECONDS = 300;\n\n// Proactive refresh fires 30 seconds before expiry\nconst PROACTIVE_REFRESH_BUFFER_SECONDS = 30;\n\nlet config: AuthConfig | null = null;\nlet isRefreshing = false;\nlet refreshPromise: Promise<TokenPair | null> | null = null;\nlet proactiveRefreshTimer: ReturnType<typeof setTimeout> | null = null;\n\n/**\n * Initialize token manager with configuration\n */\nexport function initTokenManager(authConfig: AuthConfig): void {\n config = authConfig;\n}\n\n/**\n * Get the storage instance (localStorage or sessionStorage)\n */\nfunction getStorage(): Storage {\n if (typeof window === 'undefined') {\n // SSR fallback - return a no-op storage\n return {\n getItem: () => null,\n setItem: () => {},\n removeItem: () => {},\n clear: () => {},\n key: () => null,\n length: 0,\n };\n }\n return config?.useSessionStorage ? sessionStorage : localStorage;\n}\n\n/**\n * Get storage key with prefix\n */\nfunction getKey(key: string): string {\n const prefix = config?.storagePrefix || DEFAULT_STORAGE_PREFIX;\n return `${prefix}_${key}`;\n}\n\n/**\n * Decode a JWT token without verification\n */\nexport function decodeJwt(token: string): JwtPayload | null {\n try {\n const parts = token.split('.');\n if (parts.length !== 3) return null;\n \n const payload = parts[1];\n // Handle URL-safe base64\n const base64 = payload.replace(/-/g, '+').replace(/_/g, '/');\n const jsonPayload = decodeURIComponent(\n atob(base64)\n .split('')\n .map((c) => '%' + ('00' + c.charCodeAt(0).toString(16)).slice(-2))\n .join('')\n );\n \n return JSON.parse(jsonPayload) as JwtPayload;\n } catch {\n return null;\n }\n}\n\n/**\n * Get the access token from storage\n */\nexport function getAccessToken(): string | null {\n return getStorage().getItem(getKey(ACCESS_TOKEN_KEY));\n}\n\n/**\n * Get the refresh token from storage\n */\nexport function getRefreshToken(): string | null {\n return getStorage().getItem(getKey(REFRESH_TOKEN_KEY));\n}\n\n/**\n * Get the stored token expiry timestamp (seconds since epoch)\n */\nexport function getTokenExpiry(): number | null {\n const expiry = getStorage().getItem(getKey(TOKEN_EXPIRY_KEY));\n return expiry ? parseInt(expiry, 10) : null;\n}\n\n/**\n * Store tokens in storage, including the expiry timestamp decoded from the JWT\n */\nexport function setTokens(accessToken: string, refreshToken: string): void {\n const storage = getStorage();\n storage.setItem(getKey(ACCESS_TOKEN_KEY), accessToken);\n storage.setItem(getKey(REFRESH_TOKEN_KEY), refreshToken);\n\n // Persist expiry from JWT exp claim\n const payload = decodeJwt(accessToken);\n if (payload?.exp) {\n storage.setItem(getKey(TOKEN_EXPIRY_KEY), String(payload.exp));\n }\n}\n\n/**\n * Clear all tokens from storage\n */\nexport function clearTokens(): void {\n const storage = getStorage();\n storage.removeItem(getKey(ACCESS_TOKEN_KEY));\n storage.removeItem(getKey(REFRESH_TOKEN_KEY));\n storage.removeItem(getKey(TOKEN_EXPIRY_KEY));\n cancelProactiveRefresh();\n}\n\n/**\n * Check if the access token is expired or about to expire\n */\nexport function isTokenExpired(token?: string | null): boolean {\n const accessToken = token ?? getAccessToken();\n if (!accessToken) return true;\n \n const payload = decodeJwt(accessToken);\n if (!payload || !payload.exp) return true;\n \n // Check if token expires within buffer period\n const now = Math.floor(Date.now() / 1000);\n return payload.exp <= now + EXPIRY_BUFFER_SECONDS;\n}\n\n/**\n * Check if we have a valid (non-expired) access token\n */\nexport function hasValidToken(): boolean {\n const token = getAccessToken();\n return token !== null && !isTokenExpired(token);\n}\n\n/**\n * Get user info from the current access token\n */\nexport function getUserFromToken(): JwtPayload | null {\n const token = getAccessToken();\n if (!token) return null;\n return decodeJwt(token);\n}\n\n/**\n * Refresh tokens using the refresh token\n * Handles concurrent refresh requests by returning the same promise\n */\nexport async function refreshTokens(): Promise<TokenPair | null> {\n if (!config) {\n throw new Error('TokenManager not initialized. Call initTokenManager first.');\n }\n\n const refreshToken = getRefreshToken();\n if (!refreshToken) {\n clearTokens();\n return null;\n }\n\n // If already refreshing, return the existing promise\n if (isRefreshing && refreshPromise) {\n return refreshPromise;\n }\n\n isRefreshing = true;\n refreshPromise = performRefresh(refreshToken);\n\n try {\n const result = await refreshPromise;\n return result;\n } finally {\n isRefreshing = false;\n refreshPromise = null;\n }\n}\n\n/**\n * Perform the actual token refresh request\n */\nasync function performRefresh(refreshToken: string): Promise<TokenPair | null> {\n if (!config) return null;\n\n try {\n const response = await fetch(`${config.ssoBaseUrl}/api/auth/refresh`, {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json',\n },\n body: JSON.stringify({ refreshToken }),\n });\n\n if (!response.ok) {\n clearTokens();\n config.onAuthError?.(new Error('Token refresh failed'));\n return null;\n }\n\n const data = await response.json();\n const tokens: TokenPair = {\n accessToken: data.accessToken || data.access_token,\n refreshToken: data.refreshToken || data.refresh_token,\n expiresIn: data.expiresIn || data.expires_in,\n tokenType: data.tokenType || data.token_type || 'Bearer',\n };\n\n setTokens(tokens.accessToken, tokens.refreshToken);\n config.onTokenRefresh?.(tokens);\n\n return tokens;\n } catch (error) {\n clearTokens();\n config.onAuthError?.(error instanceof Error ? error : new Error('Token refresh failed'));\n return null;\n }\n}\n\n/**\n * Get a valid access token, refreshing if necessary\n */\nexport async function getValidAccessToken(): Promise<string | null> {\n const token = getAccessToken();\n \n if (token && !isTokenExpired(token)) {\n return token;\n }\n\n const refreshed = await refreshTokens();\n return refreshed?.accessToken ?? null;\n}\n\n/**\n * Cancel any pending proactive refresh timer\n */\nexport function cancelProactiveRefresh(): void {\n if (proactiveRefreshTimer !== null) {\n clearTimeout(proactiveRefreshTimer);\n proactiveRefreshTimer = null;\n }\n}\n\n/**\n * Schedule a proactive token refresh ~30 seconds before expiry.\n * Calls `onRefreshed` with the new token pair on success so the\n * AuthProvider can update React state without a re-mount.\n */\nexport function scheduleProactiveRefresh(\n onRefreshed?: (tokens: TokenPair) => void,\n onFailed?: () => void,\n): void {\n cancelProactiveRefresh();\n\n const expiry = getTokenExpiry();\n if (!expiry) return;\n\n const now = Math.floor(Date.now() / 1000);\n const delaySeconds = expiry - now - PROACTIVE_REFRESH_BUFFER_SECONDS;\n\n // If already past the proactive window, don't schedule (the normal\n // isTokenExpired / 401 fallback will handle it)\n if (delaySeconds <= 0) return;\n\n proactiveRefreshTimer = setTimeout(async () => {\n proactiveRefreshTimer = null;\n const tokens = await refreshTokens();\n if (tokens) {\n // Re-schedule for the next cycle\n scheduleProactiveRefresh(onRefreshed, onFailed);\n onRefreshed?.(tokens);\n } else {\n onFailed?.();\n }\n }, delaySeconds * 1000);\n}\n","import type { AxiosInstance, InternalAxiosRequestConfig, AxiosResponse, AxiosError } from 'axios';\nimport { getAccessToken, getValidAccessToken, clearTokens } from './tokenManager';\nimport type { AuthConfig } from './types';\n\ninterface QueuedRequest {\n resolve: (token: string | null) => void;\n reject: (error: Error) => void;\n}\n\nlet isRefreshing = false;\nlet requestQueue: QueuedRequest[] = [];\n\n/**\n * Process queued requests after token refresh\n */\nfunction processQueue(token: string | null, error: Error | null = null): void {\n requestQueue.forEach((request) => {\n if (error) {\n request.reject(error);\n } else {\n request.resolve(token);\n }\n });\n requestQueue = [];\n}\n\n/**\n * Create and configure axios instance with auth interceptors\n */\nexport function createAuthClient(\n axiosInstance: AxiosInstance,\n config: AuthConfig\n): AxiosInstance {\n // Request interceptor - attach Bearer token\n axiosInstance.interceptors.request.use(\n async (requestConfig: InternalAxiosRequestConfig): Promise<InternalAxiosRequestConfig> => {\n // Skip auth for refresh endpoint to avoid infinite loop\n if (requestConfig.url?.includes('/api/auth/refresh')) {\n return requestConfig;\n }\n\n const token = getAccessToken();\n if (token) {\n requestConfig.headers = requestConfig.headers || {};\n requestConfig.headers.Authorization = `Bearer ${token}`;\n }\n return requestConfig;\n },\n (error: unknown) => Promise.reject(error)\n );\n\n // Response interceptor - handle 401 and refresh token\n axiosInstance.interceptors.response.use(\n (response: AxiosResponse) => response,\n async (error: AxiosError): Promise<AxiosResponse> => {\n const originalRequest = error.config as InternalAxiosRequestConfig & {\n _retry?: boolean;\n };\n\n // Only handle 401 errors\n if (error.response?.status !== 401) {\n return Promise.reject(error);\n }\n\n // Don't retry if already retried or no config\n if (originalRequest._retry || !originalRequest) {\n clearTokens();\n config.onAuthError?.(new Error('Authentication failed'));\n return Promise.reject(error);\n }\n\n // Don't retry refresh endpoint\n if (originalRequest.url?.includes('/api/auth/refresh')) {\n clearTokens();\n config.onAuthError?.(new Error('Token refresh failed'));\n return Promise.reject(error);\n }\n\n // If already refreshing, queue this request\n if (isRefreshing) {\n return new Promise((resolve, reject) => {\n requestQueue.push({\n resolve: (token) => {\n if (token) {\n originalRequest.headers = originalRequest.headers || {};\n originalRequest.headers.Authorization = `Bearer ${token}`;\n resolve(axiosInstance(originalRequest));\n } else {\n reject(new Error('Token refresh failed'));\n }\n },\n reject,\n });\n });\n }\n\n originalRequest._retry = true;\n isRefreshing = true;\n\n try {\n const token = await getValidAccessToken();\n \n if (!token) {\n processQueue(null, new Error('Token refresh failed'));\n clearTokens();\n config.onAuthError?.(new Error('Token refresh failed'));\n return Promise.reject(error);\n }\n\n processQueue(token);\n \n originalRequest.headers = originalRequest.headers || {};\n originalRequest.headers.Authorization = `Bearer ${token}`;\n \n return axiosInstance(originalRequest);\n } catch (refreshError) {\n processQueue(null, refreshError instanceof Error ? refreshError : new Error('Token refresh failed'));\n clearTokens();\n config.onAuthError?.(refreshError instanceof Error ? refreshError : new Error('Token refresh failed'));\n return Promise.reject(refreshError);\n } finally {\n isRefreshing = false;\n }\n }\n );\n\n return axiosInstance;\n}\n\n/**\n * Create a new axios instance with auth interceptors\n */\nexport function createApiClient(config: AuthConfig): AxiosInstance {\n // Dynamic import to avoid bundling axios if not used\n // eslint-disable-next-line @typescript-eslint/no-require-imports\n const axios = require('axios');\n \n const instance = axios.create({\n baseURL: config.apiBaseUrl,\n headers: {\n 'Content-Type': 'application/json',\n },\n });\n\n return createAuthClient(instance, config);\n}\n","import React, { createContext, useEffect, useState, useCallback, useMemo } from 'react';\nimport type { User, AuthState, AuthContextValue, AuthProviderProps, TokenPair, AuthConfig } from './types';\nimport {\n initTokenManager,\n getAccessToken,\n setTokens,\n clearTokens,\n isTokenExpired,\n decodeJwt,\n getValidAccessToken,\n scheduleProactiveRefresh,\n cancelProactiveRefresh,\n} from './tokenManager';\n\n// Create context with undefined default\nexport const AuthContext = createContext<AuthContextValue | undefined>(undefined);\n\n/**\n * Parse user from JWT payload\n */\nfunction parseUserFromToken(token: string): User | null {\n const payload = decodeJwt(token);\n if (!payload) return null;\n\n return {\n id: payload.sub,\n email: payload.email,\n firstName: payload.given_name,\n lastName: payload.family_name,\n displayName: payload.name,\n avatarUrl: payload.picture,\n emailVerified: payload.email_verified ?? false,\n roles: payload.roles,\n permissions: payload.permissions,\n };\n}\n\n/**\n * Build the SSO authorization URL\n */\nfunction buildAuthUrl(\n ssoBaseUrl: string,\n clientId: string,\n redirectUri: string | undefined,\n scopes: string[] = ['openid', 'email', 'profile'],\n redirectPath?: string\n): string {\n const finalRedirectUri = redirectUri || `${window.location.origin}/callback`;\n \n // Store the original path to redirect back after login\n if (redirectPath) {\n sessionStorage.setItem('arowauth_redirect_path', redirectPath);\n }\n\n const params = new URLSearchParams({\n client_id: clientId,\n redirect_uri: finalRedirectUri,\n response_type: 'token',\n scope: scopes.join(' '),\n });\n\n return `${ssoBaseUrl}/oauth/authorize?${params.toString()}`;\n}\n\n/**\n * Parse tokens from URL hash fragment (SSO callback)\n */\nfunction parseTokensFromHash(): TokenPair | null {\n if (typeof window === 'undefined') return null;\n \n const hash = window.location.hash;\n if (!hash) return null;\n\n // Parse hash fragment: #access_token=xxx&refresh_token=yyy&...\n const params = new URLSearchParams(hash.substring(1));\n \n const accessToken = params.get('access_token') || params.get('token');\n const refreshToken = params.get('refresh_token');\n\n if (accessToken && refreshToken) {\n return {\n accessToken,\n refreshToken,\n expiresIn: params.get('expires_in') ? parseInt(params.get('expires_in')!, 10) : undefined,\n tokenType: params.get('token_type') || 'Bearer',\n };\n }\n\n return null;\n}\n\n/**\n * AuthProvider component - wraps app with auth context\n */\nexport function AuthProvider(props: AuthProviderProps): React.ReactElement {\n const { children, onTokenRefresh, onAuthError, onLogout, ...config } = props;\n\n const [state, setState] = useState<AuthState>({\n user: null,\n isAuthenticated: false,\n isLoading: true,\n error: null,\n });\n\n // Initialize token manager with config\n useEffect(() => {\n const fullConfig: AuthConfig = {\n ...config,\n onTokenRefresh,\n onAuthError: (error: Error) => {\n setState((prev: AuthState) => ({ ...prev, error: error.message }));\n onAuthError?.(error);\n },\n onLogout,\n };\n initTokenManager(fullConfig);\n }, [config.ssoBaseUrl, config.clientId, config.apiBaseUrl, onTokenRefresh, onAuthError, onLogout]);\n\n // Handle SSO callback and initial auth check\n useEffect(() => {\n const startProactive = () => {\n scheduleProactiveRefresh(\n (tokens) => {\n const user = parseUserFromToken(tokens.accessToken);\n setState((prev: AuthState) => ({ ...prev, user, isAuthenticated: true, error: null }));\n onTokenRefresh?.(tokens);\n },\n () => {\n setState({ user: null, isAuthenticated: false, isLoading: false, error: null });\n },\n );\n };\n\n const initAuth = async () => {\n try {\n // Check for tokens in URL hash (SSO callback)\n const hashTokens = parseTokensFromHash();\n if (hashTokens) {\n setTokens(hashTokens.accessToken, hashTokens.refreshToken);\n \n // Clean up URL\n window.history.replaceState(null, '', window.location.pathname + window.location.search);\n \n // Redirect to original path if stored\n const redirectPath = sessionStorage.getItem('arowauth_redirect_path');\n if (redirectPath) {\n sessionStorage.removeItem('arowauth_redirect_path');\n window.history.replaceState(null, '', redirectPath);\n }\n\n onTokenRefresh?.(hashTokens);\n startProactive();\n }\n\n // Check for existing valid token\n const token = getAccessToken();\n if (token && !isTokenExpired(token)) {\n const user = parseUserFromToken(token);\n setState({\n user,\n isAuthenticated: true,\n isLoading: false,\n error: null,\n });\n startProactive();\n return;\n }\n\n // Try to refresh if we have a token but it's expired\n if (token) {\n const newToken = await getValidAccessToken();\n if (newToken) {\n const user = parseUserFromToken(newToken);\n setState({\n user,\n isAuthenticated: true,\n isLoading: false,\n error: null,\n });\n startProactive();\n return;\n }\n }\n\n // No valid auth\n setState({\n user: null,\n isAuthenticated: false,\n isLoading: false,\n error: null,\n });\n } catch (error) {\n setState({\n user: null,\n isAuthenticated: false,\n isLoading: false,\n error: error instanceof Error ? error.message : 'Authentication error',\n });\n }\n };\n\n initAuth();\n\n return () => {\n cancelProactiveRefresh();\n };\n }, [onTokenRefresh]);\n\n // Login - redirect to SSO\n const login = useCallback((redirectPath?: string) => {\n const authUrl = buildAuthUrl(\n config.ssoBaseUrl,\n config.clientId,\n config.redirectUri,\n config.scopes,\n redirectPath || window.location.pathname\n );\n window.location.href = authUrl;\n }, [config.ssoBaseUrl, config.clientId, config.redirectUri, config.scopes]);\n\n // Logout - clear tokens and optionally call SSO logout\n const logout = useCallback(async () => {\n clearTokens();\n setState({\n user: null,\n isAuthenticated: false,\n isLoading: false,\n error: null,\n });\n onLogout?.();\n }, [onLogout]);\n\n // Refresh user data from token\n const refreshUser = useCallback(async () => {\n const token = await getValidAccessToken();\n if (token) {\n const user = parseUserFromToken(token);\n setState((prev: AuthState) => ({\n ...prev,\n user,\n isAuthenticated: true,\n error: null,\n }));\n } else {\n setState({\n user: null,\n isAuthenticated: false,\n isLoading: false,\n error: null,\n });\n }\n }, []);\n\n // Memoize context value\n const contextValue = useMemo<AuthContextValue>(\n () => ({\n ...state,\n login,\n logout,\n refreshUser,\n }),\n [state, login, logout, refreshUser]\n );\n\n return (\n <AuthContext.Provider value={contextValue}>\n {children}\n </AuthContext.Provider>\n );\n}\n","import { useContext } from 'react';\nimport { AuthContext } from '../AuthProvider';\nimport type { AuthContextValue, User } from '../types';\n\n/**\n * Hook to access auth state and actions\n * \n * @returns Auth context value with user, isAuthenticated, login, logout, etc.\n * @throws Error if used outside of AuthProvider\n * \n * @example\n * ```tsx\n * function MyComponent() {\n * const { user, isAuthenticated, login, logout, isLoading } = useAuth();\n * \n * if (isLoading) return <div>Loading...</div>;\n * \n * if (!isAuthenticated) {\n * return <button onClick={() => login()}>Login</button>;\n * }\n * \n * return (\n * <div>\n * <p>Welcome, {user?.displayName || user?.email}!</p>\n * <button onClick={logout}>Logout</button>\n * </div>\n * );\n * }\n * ```\n */\nexport function useAuth(): AuthContextValue {\n const context = useContext(AuthContext);\n \n if (context === undefined) {\n throw new Error('useAuth must be used within an AuthProvider');\n }\n \n return context;\n}\n\n/**\n * Hook to check if user is authenticated (convenience wrapper)\n * \n * @returns Boolean indicating if user is authenticated\n */\nexport function useIsAuthenticated(): boolean {\n const { isAuthenticated } = useAuth();\n return isAuthenticated;\n}\n\n/**\n * Hook to get current user (convenience wrapper)\n * \n * @returns Current user or null\n */\nexport function useUser(): User | null {\n const { user } = useAuth();\n return user;\n}\n","import { useMemo, useContext } from 'react';\nimport type { AxiosInstance, InternalAxiosRequestConfig, AxiosResponse, AxiosError } from 'axios';\nimport { AuthContext } from '../AuthProvider';\nimport { getAccessToken, getValidAccessToken, clearTokens } from '../tokenManager';\n\ninterface QueuedRequest {\n resolve: (token: string | null) => void;\n reject: (error: Error) => void;\n}\n\n/**\n * Hook to get a configured axios instance with auth interceptors\n * \n * The returned axios instance will:\n * - Automatically attach Bearer token to requests\n * - Handle 401 responses by refreshing tokens and retrying\n * - Queue concurrent requests during token refresh\n * \n * @returns Configured axios instance\n * @throws Error if used outside of AuthProvider\n * \n * @example\n * ```tsx\n * function MyComponent() {\n * const client = useAuthClient();\n * \n * const fetchData = async () => {\n * try {\n * const response = await client.get('/api/data');\n * console.log(response.data);\n * } catch (error) {\n * console.error('Failed to fetch data', error);\n * }\n * };\n * \n * return <button onClick={fetchData}>Fetch Data</button>;\n * }\n * ```\n */\nexport function useAuthClient(): AxiosInstance {\n const context = useContext(AuthContext);\n \n if (context === undefined) {\n throw new Error('useAuthClient must be used within an AuthProvider');\n }\n\n const client = useMemo(() => {\n // eslint-disable-next-line @typescript-eslint/no-require-imports\n const axios = require('axios');\n \n const instance: AxiosInstance = axios.create({\n headers: {\n 'Content-Type': 'application/json',\n },\n });\n\n let isRefreshing = false;\n let requestQueue: QueuedRequest[] = [];\n\n const processQueue = (token: string | null, error: Error | null = null): void => {\n requestQueue.forEach((req) => {\n if (error) {\n req.reject(error);\n } else {\n req.resolve(token);\n }\n });\n requestQueue = [];\n };\n\n // Request interceptor\n instance.interceptors.request.use(\n async (config: InternalAxiosRequestConfig): Promise<InternalAxiosRequestConfig> => {\n if (config.url?.includes('/api/auth/refresh')) {\n return config;\n }\n const token = getAccessToken();\n if (token) {\n config.headers = config.headers || {};\n config.headers.Authorization = `Bearer ${token}`;\n }\n return config;\n },\n (error: unknown) => Promise.reject(error)\n );\n\n // Response interceptor\n instance.interceptors.response.use(\n (response: AxiosResponse) => response,\n async (error: AxiosError): Promise<AxiosResponse> => {\n const originalRequest = error.config as InternalAxiosRequestConfig & {\n _retry?: boolean;\n };\n\n if (error.response?.status !== 401 || originalRequest._retry) {\n return Promise.reject(error);\n }\n\n if (originalRequest.url?.includes('/api/auth/refresh')) {\n clearTokens();\n return Promise.reject(error);\n }\n\n if (isRefreshing) {\n return new Promise((resolve, reject) => {\n requestQueue.push({\n resolve: (token) => {\n if (token) {\n originalRequest.headers = originalRequest.headers || {};\n originalRequest.headers.Authorization = `Bearer ${token}`;\n resolve(instance(originalRequest));\n } else {\n reject(new Error('Token refresh failed'));\n }\n },\n reject,\n });\n });\n }\n\n originalRequest._retry = true;\n isRefreshing = true;\n\n try {\n const token = await getValidAccessToken();\n if (!token) {\n processQueue(null, new Error('Token refresh failed'));\n clearTokens();\n return Promise.reject(error);\n }\n\n processQueue(token);\n originalRequest.headers = originalRequest.headers || {};\n originalRequest.headers.Authorization = `Bearer ${token}`;\n return instance(originalRequest);\n } catch (refreshError) {\n processQueue(null, refreshError instanceof Error ? refreshError : new Error('Refresh failed'));\n clearTokens();\n return Promise.reject(refreshError);\n } finally {\n isRefreshing = false;\n }\n }\n );\n\n return instance;\n }, []);\n\n return client;\n}\n"]}
1
+ {"version":3,"sources":["../src/tokenManager.ts","../src/pkce.ts","../src/apiInterceptor.ts","../src/AuthProvider.tsx","../src/hooks/useAuth.ts","../src/hooks/useAuthClient.ts"],"names":["isRefreshing","config","useContext","useMemo","requestQueue","processQueue"],"mappings":"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","file":"index.mjs","sourcesContent":["import type { JwtPayload, TokenPair, AuthConfig } from './types';\n\nconst DEFAULT_STORAGE_PREFIX = 'arowauth';\nconst ACCESS_TOKEN_KEY = 'access_token';\nconst REFRESH_TOKEN_KEY = 'refresh_token';\nconst TOKEN_EXPIRY_KEY = 'token_expiry';\n\n// Buffer time before expiry to trigger refresh (5 minutes for isTokenExpired checks)\nconst EXPIRY_BUFFER_SECONDS = 300;\n\n// Proactive refresh fires 30 seconds before expiry\nconst PROACTIVE_REFRESH_BUFFER_SECONDS = 30;\n\nlet config: AuthConfig | null = null;\nlet isRefreshing = false;\nlet refreshPromise: Promise<TokenPair | null> | null = null;\nlet proactiveRefreshTimer: ReturnType<typeof setTimeout> | null = null;\n\n/**\n * Initialize token manager with configuration\n */\nexport function initTokenManager(authConfig: AuthConfig): void {\n config = authConfig;\n}\n\n/**\n * Get the storage instance (localStorage or sessionStorage)\n */\nfunction getStorage(): Storage {\n if (typeof window === 'undefined') {\n // SSR fallback - return a no-op storage\n return {\n getItem: () => null,\n setItem: () => {},\n removeItem: () => {},\n clear: () => {},\n key: () => null,\n length: 0,\n };\n }\n return config?.useSessionStorage ? sessionStorage : localStorage;\n}\n\n/**\n * Get storage key with prefix\n */\nfunction getKey(key: string): string {\n const prefix = config?.storagePrefix || DEFAULT_STORAGE_PREFIX;\n return `${prefix}_${key}`;\n}\n\n/**\n * Decode a JWT token without verification\n */\nexport function decodeJwt(token: string): JwtPayload | null {\n try {\n const parts = token.split('.');\n if (parts.length !== 3) return null;\n \n const payload = parts[1];\n // Handle URL-safe base64\n const base64 = payload.replace(/-/g, '+').replace(/_/g, '/');\n const jsonPayload = decodeURIComponent(\n atob(base64)\n .split('')\n .map((c) => '%' + ('00' + c.charCodeAt(0).toString(16)).slice(-2))\n .join('')\n );\n \n return JSON.parse(jsonPayload) as JwtPayload;\n } catch {\n return null;\n }\n}\n\n/**\n * Get the access token from storage\n */\nexport function getAccessToken(): string | null {\n return getStorage().getItem(getKey(ACCESS_TOKEN_KEY));\n}\n\n/**\n * Get the refresh token from storage\n */\nexport function getRefreshToken(): string | null {\n return getStorage().getItem(getKey(REFRESH_TOKEN_KEY));\n}\n\n/**\n * Get the stored token expiry timestamp (seconds since epoch)\n */\nexport function getTokenExpiry(): number | null {\n const expiry = getStorage().getItem(getKey(TOKEN_EXPIRY_KEY));\n return expiry ? parseInt(expiry, 10) : null;\n}\n\n/**\n * Store tokens in storage, including the expiry timestamp decoded from the JWT\n */\nexport function setTokens(accessToken: string, refreshToken: string): void {\n const storage = getStorage();\n storage.setItem(getKey(ACCESS_TOKEN_KEY), accessToken);\n storage.setItem(getKey(REFRESH_TOKEN_KEY), refreshToken);\n\n // Persist expiry from JWT exp claim\n const payload = decodeJwt(accessToken);\n if (payload?.exp) {\n storage.setItem(getKey(TOKEN_EXPIRY_KEY), String(payload.exp));\n }\n}\n\n/**\n * Clear all tokens from storage\n */\nexport function clearTokens(): void {\n const storage = getStorage();\n storage.removeItem(getKey(ACCESS_TOKEN_KEY));\n storage.removeItem(getKey(REFRESH_TOKEN_KEY));\n storage.removeItem(getKey(TOKEN_EXPIRY_KEY));\n cancelProactiveRefresh();\n}\n\n/**\n * Check if the access token is expired or about to expire\n */\nexport function isTokenExpired(token?: string | null): boolean {\n const accessToken = token ?? getAccessToken();\n if (!accessToken) return true;\n \n const payload = decodeJwt(accessToken);\n if (!payload || !payload.exp) return true;\n \n // Check if token expires within buffer period\n const now = Math.floor(Date.now() / 1000);\n return payload.exp <= now + EXPIRY_BUFFER_SECONDS;\n}\n\n/**\n * Check if we have a valid (non-expired) access token\n */\nexport function hasValidToken(): boolean {\n const token = getAccessToken();\n return token !== null && !isTokenExpired(token);\n}\n\n/**\n * Get user info from the current access token\n */\nexport function getUserFromToken(): JwtPayload | null {\n const token = getAccessToken();\n if (!token) return null;\n return decodeJwt(token);\n}\n\n/**\n * Refresh tokens using the refresh token\n * Handles concurrent refresh requests by returning the same promise\n */\nexport async function refreshTokens(): Promise<TokenPair | null> {\n if (!config) {\n throw new Error('TokenManager not initialized. Call initTokenManager first.');\n }\n\n const refreshToken = getRefreshToken();\n if (!refreshToken) {\n clearTokens();\n return null;\n }\n\n // If already refreshing, return the existing promise\n if (isRefreshing && refreshPromise) {\n return refreshPromise;\n }\n\n isRefreshing = true;\n refreshPromise = performRefresh(refreshToken);\n\n try {\n const result = await refreshPromise;\n return result;\n } finally {\n isRefreshing = false;\n refreshPromise = null;\n }\n}\n\n/**\n * Perform the actual token refresh request\n */\nasync function performRefresh(refreshToken: string): Promise<TokenPair | null> {\n if (!config) return null;\n\n try {\n const response = await fetch(`${(config.ssoApiUrl || config.ssoBaseUrl)}/api/auth/refresh`, {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json',\n },\n body: JSON.stringify({ refreshToken }),\n });\n\n if (!response.ok) {\n clearTokens();\n config.onAuthError?.(new Error('Token refresh failed'));\n return null;\n }\n\n const data = await response.json();\n const tokens: TokenPair = {\n accessToken: data.accessToken || data.access_token,\n refreshToken: data.refreshToken || data.refresh_token,\n expiresIn: data.expiresIn || data.expires_in,\n tokenType: data.tokenType || data.token_type || 'Bearer',\n };\n\n setTokens(tokens.accessToken, tokens.refreshToken);\n config.onTokenRefresh?.(tokens);\n\n return tokens;\n } catch (error) {\n clearTokens();\n config.onAuthError?.(error instanceof Error ? error : new Error('Token refresh failed'));\n return null;\n }\n}\n\n/**\n * Get a valid access token, refreshing if necessary\n */\nexport async function getValidAccessToken(): Promise<string | null> {\n const token = getAccessToken();\n \n if (token && !isTokenExpired(token)) {\n return token;\n }\n\n const refreshed = await refreshTokens();\n return refreshed?.accessToken ?? null;\n}\n\n/**\n * Cancel any pending proactive refresh timer\n */\nexport function cancelProactiveRefresh(): void {\n if (proactiveRefreshTimer !== null) {\n clearTimeout(proactiveRefreshTimer);\n proactiveRefreshTimer = null;\n }\n}\n\n/**\n * Schedule a proactive token refresh ~30 seconds before expiry.\n * Calls `onRefreshed` with the new token pair on success so the\n * AuthProvider can update React state without a re-mount.\n */\nexport function scheduleProactiveRefresh(\n onRefreshed?: (tokens: TokenPair) => void,\n onFailed?: () => void,\n): void {\n cancelProactiveRefresh();\n\n const expiry = getTokenExpiry();\n if (!expiry) return;\n\n const now = Math.floor(Date.now() / 1000);\n const delaySeconds = expiry - now - PROACTIVE_REFRESH_BUFFER_SECONDS;\n\n // If already past the proactive window, don't schedule (the normal\n // isTokenExpired / 401 fallback will handle it)\n if (delaySeconds <= 0) return;\n\n proactiveRefreshTimer = setTimeout(async () => {\n proactiveRefreshTimer = null;\n const tokens = await refreshTokens();\n if (tokens) {\n // Re-schedule for the next cycle\n scheduleProactiveRefresh(onRefreshed, onFailed);\n onRefreshed?.(tokens);\n } else {\n onFailed?.();\n }\n }, delaySeconds * 1000);\n}\n","/**\n * PKCE (Proof Key for Code Exchange) helper functions for OAuth 2.0 Authorization Code Flow\n * \n * RFC 7636: https://datatracker.ietf.org/doc/html/rfc7636\n */\n\n/**\n * Generate a cryptographically random code verifier\n * Returns a base64url-encoded string of 32 random bytes (43 characters)\n */\nexport function generateCodeVerifier(): string {\n const array = new Uint8Array(32);\n crypto.getRandomValues(array);\n return base64UrlEncode(array);\n}\n\n/**\n * Generate a code challenge from a code verifier using SHA-256\n * @param verifier - The code verifier string\n * @returns Promise resolving to the base64url-encoded SHA-256 hash\n */\nexport async function generateCodeChallenge(verifier: string): Promise<string> {\n const encoder = new TextEncoder();\n const data = encoder.encode(verifier);\n const hash = await crypto.subtle.digest('SHA-256', data);\n return base64UrlEncode(new Uint8Array(hash));\n}\n\n/**\n * Encode a byte array to base64url format (RFC 4648 Section 5)\n * @param bytes - The byte array to encode\n * @returns Base64url-encoded string\n */\nfunction base64UrlEncode(bytes: Uint8Array): string {\n let str = '';\n bytes.forEach(b => str += String.fromCharCode(b));\n return btoa(str)\n .replace(/\\+/g, '-')\n .replace(/\\//g, '_')\n .replace(/=+$/, '');\n}\n","import type { AxiosInstance, InternalAxiosRequestConfig, AxiosResponse, AxiosError } from 'axios';\nimport { getAccessToken, getValidAccessToken, clearTokens } from './tokenManager';\nimport type { AuthConfig } from './types';\n\ninterface QueuedRequest {\n resolve: (token: string | null) => void;\n reject: (error: Error) => void;\n}\n\nlet isRefreshing = false;\nlet requestQueue: QueuedRequest[] = [];\n\n/**\n * Process queued requests after token refresh\n */\nfunction processQueue(token: string | null, error: Error | null = null): void {\n requestQueue.forEach((request) => {\n if (error) {\n request.reject(error);\n } else {\n request.resolve(token);\n }\n });\n requestQueue = [];\n}\n\n/**\n * Create and configure axios instance with auth interceptors\n */\nexport function createAuthClient(\n axiosInstance: AxiosInstance,\n config: AuthConfig\n): AxiosInstance {\n // Request interceptor - attach Bearer token\n axiosInstance.interceptors.request.use(\n async (requestConfig: InternalAxiosRequestConfig): Promise<InternalAxiosRequestConfig> => {\n // Skip auth for refresh endpoint to avoid infinite loop\n if (requestConfig.url?.includes('/api/auth/refresh')) {\n return requestConfig;\n }\n\n const token = getAccessToken();\n if (token) {\n requestConfig.headers = requestConfig.headers || {};\n requestConfig.headers.Authorization = `Bearer ${token}`;\n }\n return requestConfig;\n },\n (error: unknown) => Promise.reject(error)\n );\n\n // Response interceptor - handle 401 and refresh token\n axiosInstance.interceptors.response.use(\n (response: AxiosResponse) => response,\n async (error: AxiosError): Promise<AxiosResponse> => {\n const originalRequest = error.config as InternalAxiosRequestConfig & {\n _retry?: boolean;\n };\n\n // Only handle 401 errors\n if (error.response?.status !== 401) {\n return Promise.reject(error);\n }\n\n // Don't retry if already retried or no config\n if (originalRequest._retry || !originalRequest) {\n clearTokens();\n config.onAuthError?.(new Error('Authentication failed'));\n return Promise.reject(error);\n }\n\n // Don't retry refresh endpoint\n if (originalRequest.url?.includes('/api/auth/refresh')) {\n clearTokens();\n config.onAuthError?.(new Error('Token refresh failed'));\n return Promise.reject(error);\n }\n\n // If already refreshing, queue this request\n if (isRefreshing) {\n return new Promise((resolve, reject) => {\n requestQueue.push({\n resolve: (token) => {\n if (token) {\n originalRequest.headers = originalRequest.headers || {};\n originalRequest.headers.Authorization = `Bearer ${token}`;\n resolve(axiosInstance(originalRequest));\n } else {\n reject(new Error('Token refresh failed'));\n }\n },\n reject,\n });\n });\n }\n\n originalRequest._retry = true;\n isRefreshing = true;\n\n try {\n const token = await getValidAccessToken();\n \n if (!token) {\n processQueue(null, new Error('Token refresh failed'));\n clearTokens();\n config.onAuthError?.(new Error('Token refresh failed'));\n return Promise.reject(error);\n }\n\n processQueue(token);\n \n originalRequest.headers = originalRequest.headers || {};\n originalRequest.headers.Authorization = `Bearer ${token}`;\n \n return axiosInstance(originalRequest);\n } catch (refreshError) {\n processQueue(null, refreshError instanceof Error ? refreshError : new Error('Token refresh failed'));\n clearTokens();\n config.onAuthError?.(refreshError instanceof Error ? refreshError : new Error('Token refresh failed'));\n return Promise.reject(refreshError);\n } finally {\n isRefreshing = false;\n }\n }\n );\n\n return axiosInstance;\n}\n\n/**\n * Create a new axios instance with auth interceptors\n */\nexport function createApiClient(config: AuthConfig): AxiosInstance {\n // Dynamic import to avoid bundling axios if not used\n // eslint-disable-next-line @typescript-eslint/no-require-imports\n const axios = require('axios');\n \n const instance = axios.create({\n baseURL: config.apiBaseUrl,\n headers: {\n 'Content-Type': 'application/json',\n },\n });\n\n return createAuthClient(instance, config);\n}\n","import React, { createContext, useEffect, useState, useCallback, useMemo } from 'react';\nimport type { User, AuthState, AuthContextValue, AuthProviderProps, TokenPair, AuthConfig } from './types';\nimport {\n initTokenManager,\n getAccessToken,\n setTokens,\n clearTokens,\n isTokenExpired,\n decodeJwt,\n getValidAccessToken,\n scheduleProactiveRefresh,\n cancelProactiveRefresh,\n} from './tokenManager';\nimport { generateCodeVerifier, generateCodeChallenge } from './pkce';\n\n// Create context with undefined default\nexport const AuthContext = createContext<AuthContextValue | undefined>(undefined);\n\n/**\n * Parse user from JWT payload\n */\nfunction parseUserFromToken(token: string): User | null {\n const payload = decodeJwt(token);\n if (!payload) return null;\n\n return {\n id: payload.sub,\n email: payload.email,\n firstName: payload.given_name,\n lastName: payload.family_name,\n displayName: payload.name,\n avatarUrl: payload.picture,\n emailVerified: payload.email_verified ?? false,\n roles: payload.roles,\n permissions: payload.permissions,\n };\n}\n\n/**\n * Build the SSO authorization URL with PKCE\n */\nasync function buildAuthUrl(\n ssoBaseUrl: string,\n clientId: string,\n redirectUri: string | undefined,\n scopes: string[] = ['openid', 'email', 'profile'],\n redirectPath?: string\n): Promise<string> {\n const finalRedirectUri = redirectUri || `${window.location.origin}/callback`;\n \n // Store the original path to redirect back after login\n if (redirectPath) {\n sessionStorage.setItem('arowauth_redirect_path', redirectPath);\n }\n\n // Generate PKCE parameters\n const codeVerifier = generateCodeVerifier();\n const codeChallenge = await generateCodeChallenge(codeVerifier);\n \n // Store code verifier for later use in token exchange\n sessionStorage.setItem('arow_pkce_code_verifier', codeVerifier);\n\n const params = new URLSearchParams({\n client_id: clientId,\n redirect_uri: finalRedirectUri,\n response_type: 'code',\n scope: scopes.join(' '),\n code_challenge: codeChallenge,\n code_challenge_method: 'S256',\n });\n\n return `${ssoBaseUrl}/oauth/authorize?${params.toString()}`;\n}\n\n/**\n * Parse authorization code from URL query params (PKCE callback)\n */\nfunction parseCodeFromQuery(): { code: string; state?: string } | null {\n if (typeof window === 'undefined') return null;\n \n const params = new URLSearchParams(window.location.search);\n const code = params.get('code');\n \n if (!code) return null;\n \n return {\n code,\n state: params.get('state') || undefined,\n };\n}\n\n/**\n * Exchange authorization code for tokens using PKCE\n */\nasync function exchangeCodeForTokens(\n ssoApiUrl: string,\n clientId: string,\n redirectUri: string,\n code: string\n): Promise<TokenPair | null> {\n try {\n // Retrieve and remove code verifier from session storage\n const codeVerifier = sessionStorage.getItem('arow_pkce_code_verifier');\n if (!codeVerifier) {\n throw new Error('Code verifier not found in session storage');\n }\n sessionStorage.removeItem('arow_pkce_code_verifier');\n\n // Build the token exchange request body\n const body = new URLSearchParams({\n grant_type: 'authorization_code',\n code,\n client_id: clientId,\n redirect_uri: redirectUri,\n code_verifier: codeVerifier,\n });\n\n const response = await fetch(`${ssoApiUrl}/oauth/token`, {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/x-www-form-urlencoded',\n },\n body: body.toString(),\n });\n\n if (!response.ok) {\n throw new Error(`Token exchange failed: ${response.status} ${response.statusText}`);\n }\n\n const data = await response.json();\n \n return {\n accessToken: data.access_token || data.accessToken,\n refreshToken: data.refresh_token || data.refreshToken,\n expiresIn: data.expires_in || data.expiresIn,\n tokenType: data.token_type || data.tokenType || 'Bearer',\n };\n } catch (error) {\n console.error('Failed to exchange code for tokens:', error);\n return null;\n }\n}\n\n/**\n * Parse tokens from URL hash fragment (SSO callback - DEPRECATED, v1 backward compatibility)\n */\nfunction parseTokensFromHash(): TokenPair | null {\n if (typeof window === 'undefined') return null;\n \n const hash = window.location.hash;\n if (!hash) return null;\n\n // Parse hash fragment: #access_token=xxx&refresh_token=yyy&...\n const params = new URLSearchParams(hash.substring(1));\n \n const accessToken = params.get('access_token') || params.get('token');\n const refreshToken = params.get('refresh_token');\n\n if (accessToken && refreshToken) {\n return {\n accessToken,\n refreshToken,\n expiresIn: params.get('expires_in') ? parseInt(params.get('expires_in')!, 10) : undefined,\n tokenType: params.get('token_type') || 'Bearer',\n };\n }\n\n return null;\n}\n\n/**\n * AuthProvider component - wraps app with auth context\n */\nexport function AuthProvider(props: AuthProviderProps): React.ReactElement {\n const { children, onTokenRefresh, onAuthError, onLogout, ...config } = props;\n\n const [state, setState] = useState<AuthState>({\n user: null,\n isAuthenticated: false,\n isLoading: true,\n error: null,\n });\n\n // Initialize token manager with config\n useEffect(() => {\n const fullConfig: AuthConfig = {\n ...config,\n onTokenRefresh,\n onAuthError: (error: Error) => {\n setState((prev: AuthState) => ({ ...prev, error: error.message }));\n onAuthError?.(error);\n },\n onLogout,\n };\n initTokenManager(fullConfig);\n }, [config.ssoBaseUrl, config.ssoApiUrl, config.clientId, config.apiBaseUrl, onTokenRefresh, onAuthError, onLogout]);\n\n // Handle SSO callback and initial auth check\n useEffect(() => {\n const startProactive = () => {\n scheduleProactiveRefresh(\n (tokens) => {\n const user = parseUserFromToken(tokens.accessToken);\n setState((prev: AuthState) => ({ ...prev, user, isAuthenticated: true, error: null }));\n onTokenRefresh?.(tokens);\n },\n () => {\n setState({ user: null, isAuthenticated: false, isLoading: false, error: null });\n },\n );\n };\n\n const initAuth = async () => {\n try {\n // PRIORITY 1: Check for authorization code in query params (PKCE v2 flow)\n const codeData = parseCodeFromQuery();\n if (codeData) {\n const finalRedirectUri = config.redirectUri || `${window.location.origin}/callback`;\n const tokens = await exchangeCodeForTokens(\n config.ssoApiUrl || config.ssoBaseUrl,\n config.clientId,\n finalRedirectUri,\n codeData.code\n );\n \n if (tokens) {\n setTokens(tokens.accessToken, tokens.refreshToken);\n \n // Clean up URL - remove query params\n const cleanUrl = window.location.pathname;\n window.history.replaceState(null, '', cleanUrl);\n \n // Redirect to original path if stored\n const redirectPath = sessionStorage.getItem('arowauth_redirect_path');\n if (redirectPath) {\n sessionStorage.removeItem('arowauth_redirect_path');\n window.history.replaceState(null, '', redirectPath);\n }\n\n onTokenRefresh?.(tokens);\n startProactive();\n \n const user = parseUserFromToken(tokens.accessToken);\n setState({\n user,\n isAuthenticated: true,\n isLoading: false,\n error: null,\n });\n return;\n } else {\n // Code exchange failed\n setState({\n user: null,\n isAuthenticated: false,\n isLoading: false,\n error: 'Failed to exchange authorization code for tokens',\n });\n return;\n }\n }\n\n // PRIORITY 2: Check for tokens in URL hash (v1 implicit flow - backward compatibility)\n const hashTokens = parseTokensFromHash();\n if (hashTokens) {\n setTokens(hashTokens.accessToken, hashTokens.refreshToken);\n \n // Clean up URL\n window.history.replaceState(null, '', window.location.pathname + window.location.search);\n \n // Redirect to original path if stored\n const redirectPath = sessionStorage.getItem('arowauth_redirect_path');\n if (redirectPath) {\n sessionStorage.removeItem('arowauth_redirect_path');\n window.history.replaceState(null, '', redirectPath);\n }\n\n onTokenRefresh?.(hashTokens);\n startProactive();\n }\n\n // Check for existing valid token\n const token = getAccessToken();\n if (token && !isTokenExpired(token)) {\n const user = parseUserFromToken(token);\n setState({\n user,\n isAuthenticated: true,\n isLoading: false,\n error: null,\n });\n startProactive();\n return;\n }\n\n // Try to refresh if we have a token but it's expired\n if (token) {\n const newToken = await getValidAccessToken();\n if (newToken) {\n const user = parseUserFromToken(newToken);\n setState({\n user,\n isAuthenticated: true,\n isLoading: false,\n error: null,\n });\n startProactive();\n return;\n }\n }\n\n // No valid auth\n setState({\n user: null,\n isAuthenticated: false,\n isLoading: false,\n error: null,\n });\n } catch (error) {\n setState({\n user: null,\n isAuthenticated: false,\n isLoading: false,\n error: error instanceof Error ? error.message : 'Authentication error',\n });\n }\n };\n\n initAuth();\n\n return () => {\n cancelProactiveRefresh();\n };\n }, [onTokenRefresh]);\n\n // Login - redirect to SSO\n const login = useCallback(async (redirectPath?: string) => {\n const authUrl = await buildAuthUrl(\n config.ssoBaseUrl,\n config.clientId,\n config.redirectUri,\n config.scopes,\n redirectPath || window.location.pathname\n );\n window.location.href = authUrl;\n }, [config.ssoBaseUrl, config.clientId, config.redirectUri, config.scopes]);\n\n // Logout - clear tokens and optionally call SSO logout\n const logout = useCallback(async () => {\n clearTokens();\n setState({\n user: null,\n isAuthenticated: false,\n isLoading: false,\n error: null,\n });\n onLogout?.();\n }, [onLogout]);\n\n // Refresh user data from token\n const refreshUser = useCallback(async () => {\n const token = await getValidAccessToken();\n if (token) {\n const user = parseUserFromToken(token);\n setState((prev: AuthState) => ({\n ...prev,\n user,\n isAuthenticated: true,\n error: null,\n }));\n } else {\n setState({\n user: null,\n isAuthenticated: false,\n isLoading: false,\n error: null,\n });\n }\n }, []);\n\n // Memoize context value\n const contextValue = useMemo<AuthContextValue>(\n () => ({\n ...state,\n login,\n logout,\n refreshUser,\n }),\n [state, login, logout, refreshUser]\n );\n\n return (\n <AuthContext.Provider value={contextValue}>\n {children}\n </AuthContext.Provider>\n );\n}\n","import { useContext } from 'react';\nimport { AuthContext } from '../AuthProvider';\nimport type { AuthContextValue, User } from '../types';\n\n/**\n * Hook to access auth state and actions\n * \n * @returns Auth context value with user, isAuthenticated, login, logout, etc.\n * @throws Error if used outside of AuthProvider\n * \n * @example\n * ```tsx\n * function MyComponent() {\n * const { user, isAuthenticated, login, logout, isLoading } = useAuth();\n * \n * if (isLoading) return <div>Loading...</div>;\n * \n * if (!isAuthenticated) {\n * return <button onClick={() => login()}>Login</button>;\n * }\n * \n * return (\n * <div>\n * <p>Welcome, {user?.displayName || user?.email}!</p>\n * <button onClick={logout}>Logout</button>\n * </div>\n * );\n * }\n * ```\n */\nexport function useAuth(): AuthContextValue {\n const context = useContext(AuthContext);\n \n if (context === undefined) {\n throw new Error('useAuth must be used within an AuthProvider');\n }\n \n return context;\n}\n\n/**\n * Hook to check if user is authenticated (convenience wrapper)\n * \n * @returns Boolean indicating if user is authenticated\n */\nexport function useIsAuthenticated(): boolean {\n const { isAuthenticated } = useAuth();\n return isAuthenticated;\n}\n\n/**\n * Hook to get current user (convenience wrapper)\n * \n * @returns Current user or null\n */\nexport function useUser(): User | null {\n const { user } = useAuth();\n return user;\n}\n","import { useMemo, useContext } from 'react';\nimport type { AxiosInstance, InternalAxiosRequestConfig, AxiosResponse, AxiosError } from 'axios';\nimport { AuthContext } from '../AuthProvider';\nimport { getAccessToken, getValidAccessToken, clearTokens } from '../tokenManager';\n\ninterface QueuedRequest {\n resolve: (token: string | null) => void;\n reject: (error: Error) => void;\n}\n\n/**\n * Hook to get a configured axios instance with auth interceptors\n * \n * The returned axios instance will:\n * - Automatically attach Bearer token to requests\n * - Handle 401 responses by refreshing tokens and retrying\n * - Queue concurrent requests during token refresh\n * \n * @returns Configured axios instance\n * @throws Error if used outside of AuthProvider\n * \n * @example\n * ```tsx\n * function MyComponent() {\n * const client = useAuthClient();\n * \n * const fetchData = async () => {\n * try {\n * const response = await client.get('/api/data');\n * console.log(response.data);\n * } catch (error) {\n * console.error('Failed to fetch data', error);\n * }\n * };\n * \n * return <button onClick={fetchData}>Fetch Data</button>;\n * }\n * ```\n */\nexport function useAuthClient(): AxiosInstance {\n const context = useContext(AuthContext);\n \n if (context === undefined) {\n throw new Error('useAuthClient must be used within an AuthProvider');\n }\n\n const client = useMemo(() => {\n // eslint-disable-next-line @typescript-eslint/no-require-imports\n const axios = require('axios');\n \n const instance: AxiosInstance = axios.create({\n headers: {\n 'Content-Type': 'application/json',\n },\n });\n\n let isRefreshing = false;\n let requestQueue: QueuedRequest[] = [];\n\n const processQueue = (token: string | null, error: Error | null = null): void => {\n requestQueue.forEach((req) => {\n if (error) {\n req.reject(error);\n } else {\n req.resolve(token);\n }\n });\n requestQueue = [];\n };\n\n // Request interceptor\n instance.interceptors.request.use(\n async (config: InternalAxiosRequestConfig): Promise<InternalAxiosRequestConfig> => {\n if (config.url?.includes('/api/auth/refresh')) {\n return config;\n }\n const token = getAccessToken();\n if (token) {\n config.headers = config.headers || {};\n config.headers.Authorization = `Bearer ${token}`;\n }\n return config;\n },\n (error: unknown) => Promise.reject(error)\n );\n\n // Response interceptor\n instance.interceptors.response.use(\n (response: AxiosResponse) => response,\n async (error: AxiosError): Promise<AxiosResponse> => {\n const originalRequest = error.config as InternalAxiosRequestConfig & {\n _retry?: boolean;\n };\n\n if (error.response?.status !== 401 || originalRequest._retry) {\n return Promise.reject(error);\n }\n\n if (originalRequest.url?.includes('/api/auth/refresh')) {\n clearTokens();\n return Promise.reject(error);\n }\n\n if (isRefreshing) {\n return new Promise((resolve, reject) => {\n requestQueue.push({\n resolve: (token) => {\n if (token) {\n originalRequest.headers = originalRequest.headers || {};\n originalRequest.headers.Authorization = `Bearer ${token}`;\n resolve(instance(originalRequest));\n } else {\n reject(new Error('Token refresh failed'));\n }\n },\n reject,\n });\n });\n }\n\n originalRequest._retry = true;\n isRefreshing = true;\n\n try {\n const token = await getValidAccessToken();\n if (!token) {\n processQueue(null, new Error('Token refresh failed'));\n clearTokens();\n return Promise.reject(error);\n }\n\n processQueue(token);\n originalRequest.headers = originalRequest.headers || {};\n originalRequest.headers.Authorization = `Bearer ${token}`;\n return instance(originalRequest);\n } catch (refreshError) {\n processQueue(null, refreshError instanceof Error ? refreshError : new Error('Refresh failed'));\n clearTokens();\n return Promise.reject(refreshError);\n } finally {\n isRefreshing = false;\n }\n }\n );\n\n return instance;\n }, []);\n\n return client;\n}\n"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@arow-software/auth-client",
3
- "version": "1.3.0",
3
+ "version": "2.1.0",
4
4
  "description": "Reusable auth package for ArowAuth SSO integration",
5
5
  "main": "dist/index.js",
6
6
  "module": "dist/index.mjs",