@arow-software/auth-client 1.2.0 → 1.3.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/dist/index.d.mts +16 -2
- package/dist/index.d.ts +16 -2
- package/dist/index.js +58 -0
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +56 -1
- package/dist/index.mjs.map +1 -1
- package/package.json +1 -1
package/dist/index.d.mts
CHANGED
|
@@ -133,7 +133,11 @@ declare function getAccessToken(): string | null;
|
|
|
133
133
|
*/
|
|
134
134
|
declare function getRefreshToken(): string | null;
|
|
135
135
|
/**
|
|
136
|
-
*
|
|
136
|
+
* Get the stored token expiry timestamp (seconds since epoch)
|
|
137
|
+
*/
|
|
138
|
+
declare function getTokenExpiry(): number | null;
|
|
139
|
+
/**
|
|
140
|
+
* Store tokens in storage, including the expiry timestamp decoded from the JWT
|
|
137
141
|
*/
|
|
138
142
|
declare function setTokens(accessToken: string, refreshToken: string): void;
|
|
139
143
|
/**
|
|
@@ -161,6 +165,16 @@ declare function refreshTokens(): Promise<TokenPair | null>;
|
|
|
161
165
|
* Get a valid access token, refreshing if necessary
|
|
162
166
|
*/
|
|
163
167
|
declare function getValidAccessToken(): Promise<string | null>;
|
|
168
|
+
/**
|
|
169
|
+
* Cancel any pending proactive refresh timer
|
|
170
|
+
*/
|
|
171
|
+
declare function cancelProactiveRefresh(): void;
|
|
172
|
+
/**
|
|
173
|
+
* Schedule a proactive token refresh ~30 seconds before expiry.
|
|
174
|
+
* Calls `onRefreshed` with the new token pair on success so the
|
|
175
|
+
* AuthProvider can update React state without a re-mount.
|
|
176
|
+
*/
|
|
177
|
+
declare function scheduleProactiveRefresh(onRefreshed?: (tokens: TokenPair) => void, onFailed?: () => void): void;
|
|
164
178
|
|
|
165
179
|
/**
|
|
166
180
|
* Create and configure axios instance with auth interceptors
|
|
@@ -248,4 +262,4 @@ declare function useUser(): User | null;
|
|
|
248
262
|
*/
|
|
249
263
|
declare function useAuthClient(): AxiosInstance;
|
|
250
264
|
|
|
251
|
-
export { type AuthConfig, AuthContext, type AuthContextValue, AuthProvider, type AuthProviderProps, type AuthState, type JwtPayload, type TokenPair, type User, clearTokens, createApiClient, createAuthClient, decodeJwt, getAccessToken, getRefreshToken, getUserFromToken, getValidAccessToken, hasValidToken, initTokenManager, isTokenExpired, refreshTokens, setTokens, useAuth, useAuthClient, useIsAuthenticated, useUser };
|
|
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 };
|
package/dist/index.d.ts
CHANGED
|
@@ -133,7 +133,11 @@ declare function getAccessToken(): string | null;
|
|
|
133
133
|
*/
|
|
134
134
|
declare function getRefreshToken(): string | null;
|
|
135
135
|
/**
|
|
136
|
-
*
|
|
136
|
+
* Get the stored token expiry timestamp (seconds since epoch)
|
|
137
|
+
*/
|
|
138
|
+
declare function getTokenExpiry(): number | null;
|
|
139
|
+
/**
|
|
140
|
+
* Store tokens in storage, including the expiry timestamp decoded from the JWT
|
|
137
141
|
*/
|
|
138
142
|
declare function setTokens(accessToken: string, refreshToken: string): void;
|
|
139
143
|
/**
|
|
@@ -161,6 +165,16 @@ declare function refreshTokens(): Promise<TokenPair | null>;
|
|
|
161
165
|
* Get a valid access token, refreshing if necessary
|
|
162
166
|
*/
|
|
163
167
|
declare function getValidAccessToken(): Promise<string | null>;
|
|
168
|
+
/**
|
|
169
|
+
* Cancel any pending proactive refresh timer
|
|
170
|
+
*/
|
|
171
|
+
declare function cancelProactiveRefresh(): void;
|
|
172
|
+
/**
|
|
173
|
+
* Schedule a proactive token refresh ~30 seconds before expiry.
|
|
174
|
+
* Calls `onRefreshed` with the new token pair on success so the
|
|
175
|
+
* AuthProvider can update React state without a re-mount.
|
|
176
|
+
*/
|
|
177
|
+
declare function scheduleProactiveRefresh(onRefreshed?: (tokens: TokenPair) => void, onFailed?: () => void): void;
|
|
164
178
|
|
|
165
179
|
/**
|
|
166
180
|
* Create and configure axios instance with auth interceptors
|
|
@@ -248,4 +262,4 @@ declare function useUser(): User | null;
|
|
|
248
262
|
*/
|
|
249
263
|
declare function useAuthClient(): AxiosInstance;
|
|
250
264
|
|
|
251
|
-
export { type AuthConfig, AuthContext, type AuthContextValue, AuthProvider, type AuthProviderProps, type AuthState, type JwtPayload, type TokenPair, type User, clearTokens, createApiClient, createAuthClient, decodeJwt, getAccessToken, getRefreshToken, getUserFromToken, getValidAccessToken, hasValidToken, initTokenManager, isTokenExpired, refreshTokens, setTokens, useAuth, useAuthClient, useIsAuthenticated, useUser };
|
|
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 };
|
package/dist/index.js
CHANGED
|
@@ -14,10 +14,13 @@ var __require = /* @__PURE__ */ ((x) => typeof require !== "undefined" ? require
|
|
|
14
14
|
var DEFAULT_STORAGE_PREFIX = "arowauth";
|
|
15
15
|
var ACCESS_TOKEN_KEY = "access_token";
|
|
16
16
|
var REFRESH_TOKEN_KEY = "refresh_token";
|
|
17
|
+
var TOKEN_EXPIRY_KEY = "token_expiry";
|
|
17
18
|
var EXPIRY_BUFFER_SECONDS = 300;
|
|
19
|
+
var PROACTIVE_REFRESH_BUFFER_SECONDS = 30;
|
|
18
20
|
var config = null;
|
|
19
21
|
var isRefreshing = false;
|
|
20
22
|
var refreshPromise = null;
|
|
23
|
+
var proactiveRefreshTimer = null;
|
|
21
24
|
function initTokenManager(authConfig) {
|
|
22
25
|
config = authConfig;
|
|
23
26
|
}
|
|
@@ -61,15 +64,25 @@ function getAccessToken() {
|
|
|
61
64
|
function getRefreshToken() {
|
|
62
65
|
return getStorage().getItem(getKey(REFRESH_TOKEN_KEY));
|
|
63
66
|
}
|
|
67
|
+
function getTokenExpiry() {
|
|
68
|
+
const expiry = getStorage().getItem(getKey(TOKEN_EXPIRY_KEY));
|
|
69
|
+
return expiry ? parseInt(expiry, 10) : null;
|
|
70
|
+
}
|
|
64
71
|
function setTokens(accessToken, refreshToken) {
|
|
65
72
|
const storage = getStorage();
|
|
66
73
|
storage.setItem(getKey(ACCESS_TOKEN_KEY), accessToken);
|
|
67
74
|
storage.setItem(getKey(REFRESH_TOKEN_KEY), refreshToken);
|
|
75
|
+
const payload = decodeJwt(accessToken);
|
|
76
|
+
if (payload?.exp) {
|
|
77
|
+
storage.setItem(getKey(TOKEN_EXPIRY_KEY), String(payload.exp));
|
|
78
|
+
}
|
|
68
79
|
}
|
|
69
80
|
function clearTokens() {
|
|
70
81
|
const storage = getStorage();
|
|
71
82
|
storage.removeItem(getKey(ACCESS_TOKEN_KEY));
|
|
72
83
|
storage.removeItem(getKey(REFRESH_TOKEN_KEY));
|
|
84
|
+
storage.removeItem(getKey(TOKEN_EXPIRY_KEY));
|
|
85
|
+
cancelProactiveRefresh();
|
|
73
86
|
}
|
|
74
87
|
function isTokenExpired(token) {
|
|
75
88
|
const accessToken = token ?? getAccessToken();
|
|
@@ -149,6 +162,30 @@ async function getValidAccessToken() {
|
|
|
149
162
|
const refreshed = await refreshTokens();
|
|
150
163
|
return refreshed?.accessToken ?? null;
|
|
151
164
|
}
|
|
165
|
+
function cancelProactiveRefresh() {
|
|
166
|
+
if (proactiveRefreshTimer !== null) {
|
|
167
|
+
clearTimeout(proactiveRefreshTimer);
|
|
168
|
+
proactiveRefreshTimer = null;
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
function scheduleProactiveRefresh(onRefreshed, onFailed) {
|
|
172
|
+
cancelProactiveRefresh();
|
|
173
|
+
const expiry = getTokenExpiry();
|
|
174
|
+
if (!expiry) return;
|
|
175
|
+
const now = Math.floor(Date.now() / 1e3);
|
|
176
|
+
const delaySeconds = expiry - now - PROACTIVE_REFRESH_BUFFER_SECONDS;
|
|
177
|
+
if (delaySeconds <= 0) return;
|
|
178
|
+
proactiveRefreshTimer = setTimeout(async () => {
|
|
179
|
+
proactiveRefreshTimer = null;
|
|
180
|
+
const tokens = await refreshTokens();
|
|
181
|
+
if (tokens) {
|
|
182
|
+
scheduleProactiveRefresh(onRefreshed, onFailed);
|
|
183
|
+
onRefreshed?.(tokens);
|
|
184
|
+
} else {
|
|
185
|
+
onFailed?.();
|
|
186
|
+
}
|
|
187
|
+
}, delaySeconds * 1e3);
|
|
188
|
+
}
|
|
152
189
|
|
|
153
190
|
// src/apiInterceptor.ts
|
|
154
191
|
var isRefreshing2 = false;
|
|
@@ -314,6 +351,18 @@ function AuthProvider(props) {
|
|
|
314
351
|
initTokenManager(fullConfig);
|
|
315
352
|
}, [config2.ssoBaseUrl, config2.clientId, config2.apiBaseUrl, onTokenRefresh, onAuthError, onLogout]);
|
|
316
353
|
react.useEffect(() => {
|
|
354
|
+
const startProactive = () => {
|
|
355
|
+
scheduleProactiveRefresh(
|
|
356
|
+
(tokens) => {
|
|
357
|
+
const user = parseUserFromToken(tokens.accessToken);
|
|
358
|
+
setState((prev) => ({ ...prev, user, isAuthenticated: true, error: null }));
|
|
359
|
+
onTokenRefresh?.(tokens);
|
|
360
|
+
},
|
|
361
|
+
() => {
|
|
362
|
+
setState({ user: null, isAuthenticated: false, isLoading: false, error: null });
|
|
363
|
+
}
|
|
364
|
+
);
|
|
365
|
+
};
|
|
317
366
|
const initAuth = async () => {
|
|
318
367
|
try {
|
|
319
368
|
const hashTokens = parseTokensFromHash();
|
|
@@ -326,6 +375,7 @@ function AuthProvider(props) {
|
|
|
326
375
|
window.history.replaceState(null, "", redirectPath);
|
|
327
376
|
}
|
|
328
377
|
onTokenRefresh?.(hashTokens);
|
|
378
|
+
startProactive();
|
|
329
379
|
}
|
|
330
380
|
const token = getAccessToken();
|
|
331
381
|
if (token && !isTokenExpired(token)) {
|
|
@@ -336,6 +386,7 @@ function AuthProvider(props) {
|
|
|
336
386
|
isLoading: false,
|
|
337
387
|
error: null
|
|
338
388
|
});
|
|
389
|
+
startProactive();
|
|
339
390
|
return;
|
|
340
391
|
}
|
|
341
392
|
if (token) {
|
|
@@ -348,6 +399,7 @@ function AuthProvider(props) {
|
|
|
348
399
|
isLoading: false,
|
|
349
400
|
error: null
|
|
350
401
|
});
|
|
402
|
+
startProactive();
|
|
351
403
|
return;
|
|
352
404
|
}
|
|
353
405
|
}
|
|
@@ -367,6 +419,9 @@ function AuthProvider(props) {
|
|
|
367
419
|
}
|
|
368
420
|
};
|
|
369
421
|
initAuth();
|
|
422
|
+
return () => {
|
|
423
|
+
cancelProactiveRefresh();
|
|
424
|
+
};
|
|
370
425
|
}, [onTokenRefresh]);
|
|
371
426
|
const login = react.useCallback((redirectPath) => {
|
|
372
427
|
const authUrl = buildAuthUrl(
|
|
@@ -527,18 +582,21 @@ function useAuthClient() {
|
|
|
527
582
|
|
|
528
583
|
exports.AuthContext = AuthContext;
|
|
529
584
|
exports.AuthProvider = AuthProvider;
|
|
585
|
+
exports.cancelProactiveRefresh = cancelProactiveRefresh;
|
|
530
586
|
exports.clearTokens = clearTokens;
|
|
531
587
|
exports.createApiClient = createApiClient;
|
|
532
588
|
exports.createAuthClient = createAuthClient;
|
|
533
589
|
exports.decodeJwt = decodeJwt;
|
|
534
590
|
exports.getAccessToken = getAccessToken;
|
|
535
591
|
exports.getRefreshToken = getRefreshToken;
|
|
592
|
+
exports.getTokenExpiry = getTokenExpiry;
|
|
536
593
|
exports.getUserFromToken = getUserFromToken;
|
|
537
594
|
exports.getValidAccessToken = getValidAccessToken;
|
|
538
595
|
exports.hasValidToken = hasValidToken;
|
|
539
596
|
exports.initTokenManager = initTokenManager;
|
|
540
597
|
exports.isTokenExpired = isTokenExpired;
|
|
541
598
|
exports.refreshTokens = refreshTokens;
|
|
599
|
+
exports.scheduleProactiveRefresh = scheduleProactiveRefresh;
|
|
542
600
|
exports.setTokens = setTokens;
|
|
543
601
|
exports.useAuth = useAuth;
|
|
544
602
|
exports.useAuthClient = useAuthClient;
|
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';\n\n// Buffer time before expiry to trigger refresh (5 minutes)\nconst EXPIRY_BUFFER_SECONDS = 300;\n\nlet config: AuthConfig | null = null;\nlet isRefreshing = false;\nlet refreshPromise: Promise<TokenPair | null> | 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 * Store tokens in storage\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\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}\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","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} 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 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 }\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 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 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 }, [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/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"]}
|
package/dist/index.mjs
CHANGED
|
@@ -12,10 +12,13 @@ var __require = /* @__PURE__ */ ((x) => typeof require !== "undefined" ? require
|
|
|
12
12
|
var DEFAULT_STORAGE_PREFIX = "arowauth";
|
|
13
13
|
var ACCESS_TOKEN_KEY = "access_token";
|
|
14
14
|
var REFRESH_TOKEN_KEY = "refresh_token";
|
|
15
|
+
var TOKEN_EXPIRY_KEY = "token_expiry";
|
|
15
16
|
var EXPIRY_BUFFER_SECONDS = 300;
|
|
17
|
+
var PROACTIVE_REFRESH_BUFFER_SECONDS = 30;
|
|
16
18
|
var config = null;
|
|
17
19
|
var isRefreshing = false;
|
|
18
20
|
var refreshPromise = null;
|
|
21
|
+
var proactiveRefreshTimer = null;
|
|
19
22
|
function initTokenManager(authConfig) {
|
|
20
23
|
config = authConfig;
|
|
21
24
|
}
|
|
@@ -59,15 +62,25 @@ function getAccessToken() {
|
|
|
59
62
|
function getRefreshToken() {
|
|
60
63
|
return getStorage().getItem(getKey(REFRESH_TOKEN_KEY));
|
|
61
64
|
}
|
|
65
|
+
function getTokenExpiry() {
|
|
66
|
+
const expiry = getStorage().getItem(getKey(TOKEN_EXPIRY_KEY));
|
|
67
|
+
return expiry ? parseInt(expiry, 10) : null;
|
|
68
|
+
}
|
|
62
69
|
function setTokens(accessToken, refreshToken) {
|
|
63
70
|
const storage = getStorage();
|
|
64
71
|
storage.setItem(getKey(ACCESS_TOKEN_KEY), accessToken);
|
|
65
72
|
storage.setItem(getKey(REFRESH_TOKEN_KEY), refreshToken);
|
|
73
|
+
const payload = decodeJwt(accessToken);
|
|
74
|
+
if (payload?.exp) {
|
|
75
|
+
storage.setItem(getKey(TOKEN_EXPIRY_KEY), String(payload.exp));
|
|
76
|
+
}
|
|
66
77
|
}
|
|
67
78
|
function clearTokens() {
|
|
68
79
|
const storage = getStorage();
|
|
69
80
|
storage.removeItem(getKey(ACCESS_TOKEN_KEY));
|
|
70
81
|
storage.removeItem(getKey(REFRESH_TOKEN_KEY));
|
|
82
|
+
storage.removeItem(getKey(TOKEN_EXPIRY_KEY));
|
|
83
|
+
cancelProactiveRefresh();
|
|
71
84
|
}
|
|
72
85
|
function isTokenExpired(token) {
|
|
73
86
|
const accessToken = token ?? getAccessToken();
|
|
@@ -147,6 +160,30 @@ async function getValidAccessToken() {
|
|
|
147
160
|
const refreshed = await refreshTokens();
|
|
148
161
|
return refreshed?.accessToken ?? null;
|
|
149
162
|
}
|
|
163
|
+
function cancelProactiveRefresh() {
|
|
164
|
+
if (proactiveRefreshTimer !== null) {
|
|
165
|
+
clearTimeout(proactiveRefreshTimer);
|
|
166
|
+
proactiveRefreshTimer = null;
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
function scheduleProactiveRefresh(onRefreshed, onFailed) {
|
|
170
|
+
cancelProactiveRefresh();
|
|
171
|
+
const expiry = getTokenExpiry();
|
|
172
|
+
if (!expiry) return;
|
|
173
|
+
const now = Math.floor(Date.now() / 1e3);
|
|
174
|
+
const delaySeconds = expiry - now - PROACTIVE_REFRESH_BUFFER_SECONDS;
|
|
175
|
+
if (delaySeconds <= 0) return;
|
|
176
|
+
proactiveRefreshTimer = setTimeout(async () => {
|
|
177
|
+
proactiveRefreshTimer = null;
|
|
178
|
+
const tokens = await refreshTokens();
|
|
179
|
+
if (tokens) {
|
|
180
|
+
scheduleProactiveRefresh(onRefreshed, onFailed);
|
|
181
|
+
onRefreshed?.(tokens);
|
|
182
|
+
} else {
|
|
183
|
+
onFailed?.();
|
|
184
|
+
}
|
|
185
|
+
}, delaySeconds * 1e3);
|
|
186
|
+
}
|
|
150
187
|
|
|
151
188
|
// src/apiInterceptor.ts
|
|
152
189
|
var isRefreshing2 = false;
|
|
@@ -312,6 +349,18 @@ function AuthProvider(props) {
|
|
|
312
349
|
initTokenManager(fullConfig);
|
|
313
350
|
}, [config2.ssoBaseUrl, config2.clientId, config2.apiBaseUrl, onTokenRefresh, onAuthError, onLogout]);
|
|
314
351
|
useEffect(() => {
|
|
352
|
+
const startProactive = () => {
|
|
353
|
+
scheduleProactiveRefresh(
|
|
354
|
+
(tokens) => {
|
|
355
|
+
const user = parseUserFromToken(tokens.accessToken);
|
|
356
|
+
setState((prev) => ({ ...prev, user, isAuthenticated: true, error: null }));
|
|
357
|
+
onTokenRefresh?.(tokens);
|
|
358
|
+
},
|
|
359
|
+
() => {
|
|
360
|
+
setState({ user: null, isAuthenticated: false, isLoading: false, error: null });
|
|
361
|
+
}
|
|
362
|
+
);
|
|
363
|
+
};
|
|
315
364
|
const initAuth = async () => {
|
|
316
365
|
try {
|
|
317
366
|
const hashTokens = parseTokensFromHash();
|
|
@@ -324,6 +373,7 @@ function AuthProvider(props) {
|
|
|
324
373
|
window.history.replaceState(null, "", redirectPath);
|
|
325
374
|
}
|
|
326
375
|
onTokenRefresh?.(hashTokens);
|
|
376
|
+
startProactive();
|
|
327
377
|
}
|
|
328
378
|
const token = getAccessToken();
|
|
329
379
|
if (token && !isTokenExpired(token)) {
|
|
@@ -334,6 +384,7 @@ function AuthProvider(props) {
|
|
|
334
384
|
isLoading: false,
|
|
335
385
|
error: null
|
|
336
386
|
});
|
|
387
|
+
startProactive();
|
|
337
388
|
return;
|
|
338
389
|
}
|
|
339
390
|
if (token) {
|
|
@@ -346,6 +397,7 @@ function AuthProvider(props) {
|
|
|
346
397
|
isLoading: false,
|
|
347
398
|
error: null
|
|
348
399
|
});
|
|
400
|
+
startProactive();
|
|
349
401
|
return;
|
|
350
402
|
}
|
|
351
403
|
}
|
|
@@ -365,6 +417,9 @@ function AuthProvider(props) {
|
|
|
365
417
|
}
|
|
366
418
|
};
|
|
367
419
|
initAuth();
|
|
420
|
+
return () => {
|
|
421
|
+
cancelProactiveRefresh();
|
|
422
|
+
};
|
|
368
423
|
}, [onTokenRefresh]);
|
|
369
424
|
const login = useCallback((redirectPath) => {
|
|
370
425
|
const authUrl = buildAuthUrl(
|
|
@@ -523,6 +578,6 @@ function useAuthClient() {
|
|
|
523
578
|
return client;
|
|
524
579
|
}
|
|
525
580
|
|
|
526
|
-
export { AuthContext, AuthProvider, clearTokens, createApiClient, createAuthClient, decodeJwt, getAccessToken, getRefreshToken, getUserFromToken, getValidAccessToken, hasValidToken, initTokenManager, isTokenExpired, refreshTokens, setTokens, useAuth, useAuthClient, useIsAuthenticated, useUser };
|
|
581
|
+
export { AuthContext, AuthProvider, cancelProactiveRefresh, clearTokens, createApiClient, createAuthClient, decodeJwt, getAccessToken, getRefreshToken, getTokenExpiry, getUserFromToken, getValidAccessToken, hasValidToken, initTokenManager, isTokenExpired, refreshTokens, scheduleProactiveRefresh, setTokens, useAuth, useAuthClient, useIsAuthenticated, useUser };
|
|
527
582
|
//# sourceMappingURL=index.mjs.map
|
|
528
583
|
//# sourceMappingURL=index.mjs.map
|
package/dist/index.mjs.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","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';\n\n// Buffer time before expiry to trigger refresh (5 minutes)\nconst EXPIRY_BUFFER_SECONDS = 300;\n\nlet config: AuthConfig | null = null;\nlet isRefreshing = false;\nlet refreshPromise: Promise<TokenPair | null> | 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 * Store tokens in storage\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\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}\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","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} 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 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 }\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 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 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 }, [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/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"]}
|