@imapps/web-utils 0.5.1
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/build/index.d.mts +118 -0
- package/build/index.d.ts +118 -0
- package/build/index.js +443 -0
- package/build/index.js.map +1 -0
- package/build/index.mjs +395 -0
- package/build/index.mjs.map +1 -0
- package/package.json +46 -0
|
@@ -0,0 +1,118 @@
|
|
|
1
|
+
import * as react_jsx_runtime from 'react/jsx-runtime';
|
|
2
|
+
import { ReactNode } from 'react';
|
|
3
|
+
|
|
4
|
+
interface AuthConfig {
|
|
5
|
+
authUrl: string;
|
|
6
|
+
storageType?: 'localStorage' | 'sessionStorage';
|
|
7
|
+
accessTokenKey?: string;
|
|
8
|
+
refreshTokenCookieName?: string;
|
|
9
|
+
endpoints?: {
|
|
10
|
+
refresh?: string;
|
|
11
|
+
logout?: string;
|
|
12
|
+
};
|
|
13
|
+
}
|
|
14
|
+
interface UserInfo {
|
|
15
|
+
username: string;
|
|
16
|
+
id: string;
|
|
17
|
+
[key: string]: string | number | boolean;
|
|
18
|
+
}
|
|
19
|
+
interface DecodedToken {
|
|
20
|
+
username: string;
|
|
21
|
+
id: string;
|
|
22
|
+
exp: number;
|
|
23
|
+
iat: number;
|
|
24
|
+
[key: string]: string | number | boolean;
|
|
25
|
+
}
|
|
26
|
+
interface RefreshTokenResponse {
|
|
27
|
+
accessToken: string;
|
|
28
|
+
refreshToken?: string;
|
|
29
|
+
expiresIn: number;
|
|
30
|
+
}
|
|
31
|
+
interface AuthContextType {
|
|
32
|
+
accessToken: string | null;
|
|
33
|
+
isAuthenticated: boolean;
|
|
34
|
+
login: (accessToken: string) => void;
|
|
35
|
+
logout: () => Promise<void>;
|
|
36
|
+
}
|
|
37
|
+
interface UserContextType {
|
|
38
|
+
user: UserInfo | null;
|
|
39
|
+
setUser: (user: UserInfo | null) => void;
|
|
40
|
+
updateUserFromToken: (token: string) => void;
|
|
41
|
+
clearUser: () => void;
|
|
42
|
+
}
|
|
43
|
+
interface ConfigState {
|
|
44
|
+
config: AuthConfig | null;
|
|
45
|
+
isLoading: boolean;
|
|
46
|
+
error: string | null;
|
|
47
|
+
}
|
|
48
|
+
interface AuthProviderProps {
|
|
49
|
+
children: ReactNode;
|
|
50
|
+
config?: AuthConfig;
|
|
51
|
+
}
|
|
52
|
+
interface UserProviderProps {
|
|
53
|
+
children: ReactNode;
|
|
54
|
+
}
|
|
55
|
+
interface ProtectedRouteProps {
|
|
56
|
+
children: ReactNode;
|
|
57
|
+
fallbackPath?: string;
|
|
58
|
+
}
|
|
59
|
+
interface UseAuthRedirectOptions {
|
|
60
|
+
redirectTo?: string;
|
|
61
|
+
redirectFrom?: string;
|
|
62
|
+
condition?: 'authenticated' | 'unauthenticated';
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
declare const ProtectedRoute: ({ children, fallbackPath }: ProtectedRouteProps) => react_jsx_runtime.JSX.Element;
|
|
66
|
+
|
|
67
|
+
interface AuthConfigProviderProps {
|
|
68
|
+
children: ReactNode;
|
|
69
|
+
config: AuthConfig;
|
|
70
|
+
}
|
|
71
|
+
declare const AuthConfigProvider: ({ children, config }: AuthConfigProviderProps) => react_jsx_runtime.JSX.Element;
|
|
72
|
+
declare const useAuthConfig: () => AuthConfig;
|
|
73
|
+
|
|
74
|
+
declare const AuthProvider: ({ children }: {
|
|
75
|
+
children: ReactNode;
|
|
76
|
+
}) => react_jsx_runtime.JSX.Element;
|
|
77
|
+
declare const useAuth: () => AuthContextType;
|
|
78
|
+
|
|
79
|
+
declare const UserProvider: ({ children }: {
|
|
80
|
+
children: ReactNode;
|
|
81
|
+
}) => react_jsx_runtime.JSX.Element;
|
|
82
|
+
declare const useUser: () => UserContextType;
|
|
83
|
+
|
|
84
|
+
declare const useAuthRedirect: (options?: UseAuthRedirectOptions) => {
|
|
85
|
+
isAuthenticated: boolean;
|
|
86
|
+
};
|
|
87
|
+
declare const useRedirectIfAuthenticated: (to?: string, from?: string) => {
|
|
88
|
+
isAuthenticated: boolean;
|
|
89
|
+
};
|
|
90
|
+
declare const useRedirectIfUnauthenticated: (to?: string) => {
|
|
91
|
+
isAuthenticated: boolean;
|
|
92
|
+
};
|
|
93
|
+
|
|
94
|
+
declare const useTokenInitialization: () => {
|
|
95
|
+
isInitializing: boolean;
|
|
96
|
+
};
|
|
97
|
+
|
|
98
|
+
declare const useTokenRefresh: () => {
|
|
99
|
+
refreshTokens: () => Promise<string>;
|
|
100
|
+
getValidAccessToken: () => Promise<string>;
|
|
101
|
+
hasRefreshToken: () => boolean;
|
|
102
|
+
clearTokens: () => void;
|
|
103
|
+
};
|
|
104
|
+
|
|
105
|
+
declare const decodeJWT: (token: string) => DecodedToken | null;
|
|
106
|
+
declare const isTokenExpired: (token: string) => boolean;
|
|
107
|
+
declare const getTokenExpirationTime: (token: string) => Date | null;
|
|
108
|
+
declare const extractUserFromToken: (token: string) => UserInfo | null;
|
|
109
|
+
|
|
110
|
+
declare const tryRefreshToken: (config: AuthConfig) => Promise<string | null>;
|
|
111
|
+
declare const clearRefreshTokenCookie: (cookieName?: string) => void;
|
|
112
|
+
declare const refreshAccessToken: (config: AuthConfig) => Promise<string>;
|
|
113
|
+
declare const withTokenRefresh: <T>(requestFn: () => Promise<T>, onTokenRefresh: (newToken: string) => void, onTokenClear: () => void, config: AuthConfig) => Promise<T>;
|
|
114
|
+
declare const getStorageItem: (key: string, storageType?: "localStorage" | "sessionStorage") => string | null;
|
|
115
|
+
declare const setStorageItem: (key: string, value: string, storageType?: "localStorage" | "sessionStorage") => void;
|
|
116
|
+
declare const removeStorageItem: (key: string, storageType?: "localStorage" | "sessionStorage") => void;
|
|
117
|
+
|
|
118
|
+
export { type AuthConfig, AuthConfigProvider, type AuthContextType, AuthProvider, type AuthProviderProps, type ConfigState, type DecodedToken, ProtectedRoute, type ProtectedRouteProps, type RefreshTokenResponse, type UseAuthRedirectOptions, type UserContextType, type UserInfo, UserProvider, type UserProviderProps, clearRefreshTokenCookie, decodeJWT, extractUserFromToken, getStorageItem, getTokenExpirationTime, isTokenExpired, refreshAccessToken, removeStorageItem, setStorageItem, tryRefreshToken, useAuth, useAuthConfig, useAuthRedirect, useRedirectIfAuthenticated, useRedirectIfUnauthenticated, useTokenInitialization, useTokenRefresh, useUser, withTokenRefresh };
|
package/build/index.d.ts
ADDED
|
@@ -0,0 +1,118 @@
|
|
|
1
|
+
import * as react_jsx_runtime from 'react/jsx-runtime';
|
|
2
|
+
import { ReactNode } from 'react';
|
|
3
|
+
|
|
4
|
+
interface AuthConfig {
|
|
5
|
+
authUrl: string;
|
|
6
|
+
storageType?: 'localStorage' | 'sessionStorage';
|
|
7
|
+
accessTokenKey?: string;
|
|
8
|
+
refreshTokenCookieName?: string;
|
|
9
|
+
endpoints?: {
|
|
10
|
+
refresh?: string;
|
|
11
|
+
logout?: string;
|
|
12
|
+
};
|
|
13
|
+
}
|
|
14
|
+
interface UserInfo {
|
|
15
|
+
username: string;
|
|
16
|
+
id: string;
|
|
17
|
+
[key: string]: string | number | boolean;
|
|
18
|
+
}
|
|
19
|
+
interface DecodedToken {
|
|
20
|
+
username: string;
|
|
21
|
+
id: string;
|
|
22
|
+
exp: number;
|
|
23
|
+
iat: number;
|
|
24
|
+
[key: string]: string | number | boolean;
|
|
25
|
+
}
|
|
26
|
+
interface RefreshTokenResponse {
|
|
27
|
+
accessToken: string;
|
|
28
|
+
refreshToken?: string;
|
|
29
|
+
expiresIn: number;
|
|
30
|
+
}
|
|
31
|
+
interface AuthContextType {
|
|
32
|
+
accessToken: string | null;
|
|
33
|
+
isAuthenticated: boolean;
|
|
34
|
+
login: (accessToken: string) => void;
|
|
35
|
+
logout: () => Promise<void>;
|
|
36
|
+
}
|
|
37
|
+
interface UserContextType {
|
|
38
|
+
user: UserInfo | null;
|
|
39
|
+
setUser: (user: UserInfo | null) => void;
|
|
40
|
+
updateUserFromToken: (token: string) => void;
|
|
41
|
+
clearUser: () => void;
|
|
42
|
+
}
|
|
43
|
+
interface ConfigState {
|
|
44
|
+
config: AuthConfig | null;
|
|
45
|
+
isLoading: boolean;
|
|
46
|
+
error: string | null;
|
|
47
|
+
}
|
|
48
|
+
interface AuthProviderProps {
|
|
49
|
+
children: ReactNode;
|
|
50
|
+
config?: AuthConfig;
|
|
51
|
+
}
|
|
52
|
+
interface UserProviderProps {
|
|
53
|
+
children: ReactNode;
|
|
54
|
+
}
|
|
55
|
+
interface ProtectedRouteProps {
|
|
56
|
+
children: ReactNode;
|
|
57
|
+
fallbackPath?: string;
|
|
58
|
+
}
|
|
59
|
+
interface UseAuthRedirectOptions {
|
|
60
|
+
redirectTo?: string;
|
|
61
|
+
redirectFrom?: string;
|
|
62
|
+
condition?: 'authenticated' | 'unauthenticated';
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
declare const ProtectedRoute: ({ children, fallbackPath }: ProtectedRouteProps) => react_jsx_runtime.JSX.Element;
|
|
66
|
+
|
|
67
|
+
interface AuthConfigProviderProps {
|
|
68
|
+
children: ReactNode;
|
|
69
|
+
config: AuthConfig;
|
|
70
|
+
}
|
|
71
|
+
declare const AuthConfigProvider: ({ children, config }: AuthConfigProviderProps) => react_jsx_runtime.JSX.Element;
|
|
72
|
+
declare const useAuthConfig: () => AuthConfig;
|
|
73
|
+
|
|
74
|
+
declare const AuthProvider: ({ children }: {
|
|
75
|
+
children: ReactNode;
|
|
76
|
+
}) => react_jsx_runtime.JSX.Element;
|
|
77
|
+
declare const useAuth: () => AuthContextType;
|
|
78
|
+
|
|
79
|
+
declare const UserProvider: ({ children }: {
|
|
80
|
+
children: ReactNode;
|
|
81
|
+
}) => react_jsx_runtime.JSX.Element;
|
|
82
|
+
declare const useUser: () => UserContextType;
|
|
83
|
+
|
|
84
|
+
declare const useAuthRedirect: (options?: UseAuthRedirectOptions) => {
|
|
85
|
+
isAuthenticated: boolean;
|
|
86
|
+
};
|
|
87
|
+
declare const useRedirectIfAuthenticated: (to?: string, from?: string) => {
|
|
88
|
+
isAuthenticated: boolean;
|
|
89
|
+
};
|
|
90
|
+
declare const useRedirectIfUnauthenticated: (to?: string) => {
|
|
91
|
+
isAuthenticated: boolean;
|
|
92
|
+
};
|
|
93
|
+
|
|
94
|
+
declare const useTokenInitialization: () => {
|
|
95
|
+
isInitializing: boolean;
|
|
96
|
+
};
|
|
97
|
+
|
|
98
|
+
declare const useTokenRefresh: () => {
|
|
99
|
+
refreshTokens: () => Promise<string>;
|
|
100
|
+
getValidAccessToken: () => Promise<string>;
|
|
101
|
+
hasRefreshToken: () => boolean;
|
|
102
|
+
clearTokens: () => void;
|
|
103
|
+
};
|
|
104
|
+
|
|
105
|
+
declare const decodeJWT: (token: string) => DecodedToken | null;
|
|
106
|
+
declare const isTokenExpired: (token: string) => boolean;
|
|
107
|
+
declare const getTokenExpirationTime: (token: string) => Date | null;
|
|
108
|
+
declare const extractUserFromToken: (token: string) => UserInfo | null;
|
|
109
|
+
|
|
110
|
+
declare const tryRefreshToken: (config: AuthConfig) => Promise<string | null>;
|
|
111
|
+
declare const clearRefreshTokenCookie: (cookieName?: string) => void;
|
|
112
|
+
declare const refreshAccessToken: (config: AuthConfig) => Promise<string>;
|
|
113
|
+
declare const withTokenRefresh: <T>(requestFn: () => Promise<T>, onTokenRefresh: (newToken: string) => void, onTokenClear: () => void, config: AuthConfig) => Promise<T>;
|
|
114
|
+
declare const getStorageItem: (key: string, storageType?: "localStorage" | "sessionStorage") => string | null;
|
|
115
|
+
declare const setStorageItem: (key: string, value: string, storageType?: "localStorage" | "sessionStorage") => void;
|
|
116
|
+
declare const removeStorageItem: (key: string, storageType?: "localStorage" | "sessionStorage") => void;
|
|
117
|
+
|
|
118
|
+
export { type AuthConfig, AuthConfigProvider, type AuthContextType, AuthProvider, type AuthProviderProps, type ConfigState, type DecodedToken, ProtectedRoute, type ProtectedRouteProps, type RefreshTokenResponse, type UseAuthRedirectOptions, type UserContextType, type UserInfo, UserProvider, type UserProviderProps, clearRefreshTokenCookie, decodeJWT, extractUserFromToken, getStorageItem, getTokenExpirationTime, isTokenExpired, refreshAccessToken, removeStorageItem, setStorageItem, tryRefreshToken, useAuth, useAuthConfig, useAuthRedirect, useRedirectIfAuthenticated, useRedirectIfUnauthenticated, useTokenInitialization, useTokenRefresh, useUser, withTokenRefresh };
|
package/build/index.js
ADDED
|
@@ -0,0 +1,443 @@
|
|
|
1
|
+
var __defProp = Object.defineProperty;
|
|
2
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
3
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
4
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
5
|
+
var __export = (target, all) => {
|
|
6
|
+
for (var name in all)
|
|
7
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
8
|
+
};
|
|
9
|
+
var __copyProps = (to, from, except, desc) => {
|
|
10
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
11
|
+
for (let key of __getOwnPropNames(from))
|
|
12
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
13
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
14
|
+
}
|
|
15
|
+
return to;
|
|
16
|
+
};
|
|
17
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
18
|
+
|
|
19
|
+
// src/index.ts
|
|
20
|
+
var index_exports = {};
|
|
21
|
+
__export(index_exports, {
|
|
22
|
+
AuthConfigProvider: () => AuthConfigProvider,
|
|
23
|
+
AuthProvider: () => AuthProvider,
|
|
24
|
+
ProtectedRoute: () => ProtectedRoute,
|
|
25
|
+
UserProvider: () => UserProvider,
|
|
26
|
+
clearRefreshTokenCookie: () => clearRefreshTokenCookie,
|
|
27
|
+
decodeJWT: () => decodeJWT,
|
|
28
|
+
extractUserFromToken: () => extractUserFromToken,
|
|
29
|
+
getStorageItem: () => getStorageItem,
|
|
30
|
+
getTokenExpirationTime: () => getTokenExpirationTime,
|
|
31
|
+
isTokenExpired: () => isTokenExpired,
|
|
32
|
+
refreshAccessToken: () => refreshAccessToken,
|
|
33
|
+
removeStorageItem: () => removeStorageItem,
|
|
34
|
+
setStorageItem: () => setStorageItem,
|
|
35
|
+
tryRefreshToken: () => tryRefreshToken,
|
|
36
|
+
useAuth: () => useAuth,
|
|
37
|
+
useAuthConfig: () => useAuthConfig,
|
|
38
|
+
useAuthRedirect: () => useAuthRedirect,
|
|
39
|
+
useRedirectIfAuthenticated: () => useRedirectIfAuthenticated,
|
|
40
|
+
useRedirectIfUnauthenticated: () => useRedirectIfUnauthenticated,
|
|
41
|
+
useTokenInitialization: () => useTokenInitialization,
|
|
42
|
+
useTokenRefresh: () => useTokenRefresh,
|
|
43
|
+
useUser: () => useUser,
|
|
44
|
+
withTokenRefresh: () => withTokenRefresh
|
|
45
|
+
});
|
|
46
|
+
module.exports = __toCommonJS(index_exports);
|
|
47
|
+
|
|
48
|
+
// src/auth/components/ProtectedRoute.tsx
|
|
49
|
+
var import_react_router_dom = require("react-router-dom");
|
|
50
|
+
|
|
51
|
+
// src/auth/contexts/AuthContext.tsx
|
|
52
|
+
var import_react3 = require("react");
|
|
53
|
+
|
|
54
|
+
// src/auth/utils/jwtUtils.ts
|
|
55
|
+
var decodeJWT = (token) => {
|
|
56
|
+
try {
|
|
57
|
+
const parts = token.split(".");
|
|
58
|
+
if (parts.length !== 3) {
|
|
59
|
+
throw new Error("Invalid JWT token format");
|
|
60
|
+
}
|
|
61
|
+
const payload = parts[1];
|
|
62
|
+
const paddedPayload = payload + "=".repeat((4 - payload.length % 4) % 4);
|
|
63
|
+
const decodedPayload = atob(paddedPayload);
|
|
64
|
+
const parsedPayload = JSON.parse(decodedPayload);
|
|
65
|
+
return parsedPayload;
|
|
66
|
+
} catch (error) {
|
|
67
|
+
console.error("Failed to decode JWT token:", error);
|
|
68
|
+
return null;
|
|
69
|
+
}
|
|
70
|
+
};
|
|
71
|
+
var isTokenExpired = (token) => {
|
|
72
|
+
const decoded = decodeJWT(token);
|
|
73
|
+
if (!decoded) {
|
|
74
|
+
return true;
|
|
75
|
+
}
|
|
76
|
+
const currentTime = Date.now() / 1e3;
|
|
77
|
+
return decoded.exp < currentTime;
|
|
78
|
+
};
|
|
79
|
+
var getTokenExpirationTime = (token) => {
|
|
80
|
+
const decoded = decodeJWT(token);
|
|
81
|
+
if (!decoded) {
|
|
82
|
+
return null;
|
|
83
|
+
}
|
|
84
|
+
return new Date(decoded.exp * 1e3);
|
|
85
|
+
};
|
|
86
|
+
var extractUserFromToken = (token) => {
|
|
87
|
+
const decoded = decodeJWT(token);
|
|
88
|
+
if (!decoded || !decoded.username || !decoded.id) {
|
|
89
|
+
return null;
|
|
90
|
+
}
|
|
91
|
+
return {
|
|
92
|
+
username: decoded.username,
|
|
93
|
+
id: decoded.id
|
|
94
|
+
};
|
|
95
|
+
};
|
|
96
|
+
|
|
97
|
+
// src/auth/utils/tokenUtils.ts
|
|
98
|
+
var tryRefreshToken = async (config) => {
|
|
99
|
+
try {
|
|
100
|
+
const refreshEndpoint = config.endpoints?.refresh || "/refresh";
|
|
101
|
+
const response = await fetch(`${config.authUrl}${refreshEndpoint}`, {
|
|
102
|
+
method: "POST",
|
|
103
|
+
credentials: "include"
|
|
104
|
+
});
|
|
105
|
+
if (!response.ok) {
|
|
106
|
+
return null;
|
|
107
|
+
}
|
|
108
|
+
const data = await response.json();
|
|
109
|
+
return data.accessToken;
|
|
110
|
+
} catch {
|
|
111
|
+
return null;
|
|
112
|
+
}
|
|
113
|
+
};
|
|
114
|
+
var clearRefreshTokenCookie = (cookieName = "refreshToken") => {
|
|
115
|
+
document.cookie = `${cookieName}=; expires=Thu, 01 Jan 1970 00:00:00 UTC; path=/;`;
|
|
116
|
+
};
|
|
117
|
+
var refreshAccessToken = async (config) => {
|
|
118
|
+
try {
|
|
119
|
+
const refreshEndpoint = config.endpoints?.refresh || "/refresh";
|
|
120
|
+
const response = await fetch(`${config.authUrl}${refreshEndpoint}`, {
|
|
121
|
+
method: "POST",
|
|
122
|
+
credentials: "include"
|
|
123
|
+
});
|
|
124
|
+
if (!response.ok) {
|
|
125
|
+
if (response.status === 401 || response.status === 403) {
|
|
126
|
+
clearRefreshTokenCookie(config.refreshTokenCookieName);
|
|
127
|
+
throw new Error("Refresh token expired. Please log in again.");
|
|
128
|
+
} else {
|
|
129
|
+
throw new Error(`Failed to refresh token: ${response.status}`);
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
const data = await response.json();
|
|
133
|
+
return data.accessToken;
|
|
134
|
+
} catch (error) {
|
|
135
|
+
clearRefreshTokenCookie(config.refreshTokenCookieName);
|
|
136
|
+
throw error;
|
|
137
|
+
}
|
|
138
|
+
};
|
|
139
|
+
var withTokenRefresh = async (requestFn, onTokenRefresh, onTokenClear, config) => {
|
|
140
|
+
try {
|
|
141
|
+
return await requestFn();
|
|
142
|
+
} catch (error) {
|
|
143
|
+
if (error instanceof Error && error.message.includes("401")) {
|
|
144
|
+
try {
|
|
145
|
+
const newAccessToken = await tryRefreshToken(config);
|
|
146
|
+
if (newAccessToken) {
|
|
147
|
+
onTokenRefresh(newAccessToken);
|
|
148
|
+
return await requestFn();
|
|
149
|
+
} else {
|
|
150
|
+
onTokenClear();
|
|
151
|
+
clearRefreshTokenCookie(config.refreshTokenCookieName);
|
|
152
|
+
throw new Error("No valid refresh token available");
|
|
153
|
+
}
|
|
154
|
+
} catch (refreshError) {
|
|
155
|
+
onTokenClear();
|
|
156
|
+
clearRefreshTokenCookie(config.refreshTokenCookieName);
|
|
157
|
+
throw refreshError;
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
throw error;
|
|
161
|
+
}
|
|
162
|
+
};
|
|
163
|
+
var getStorageItem = (key, storageType = "localStorage") => {
|
|
164
|
+
if (typeof window === "undefined") return null;
|
|
165
|
+
const storage = storageType === "localStorage" ? window.localStorage : window.sessionStorage;
|
|
166
|
+
return storage.getItem(key);
|
|
167
|
+
};
|
|
168
|
+
var setStorageItem = (key, value, storageType = "localStorage") => {
|
|
169
|
+
if (typeof window === "undefined") return;
|
|
170
|
+
const storage = storageType === "localStorage" ? window.localStorage : window.sessionStorage;
|
|
171
|
+
storage.setItem(key, value);
|
|
172
|
+
};
|
|
173
|
+
var removeStorageItem = (key, storageType = "localStorage") => {
|
|
174
|
+
if (typeof window === "undefined") return;
|
|
175
|
+
const storage = storageType === "localStorage" ? window.localStorage : window.sessionStorage;
|
|
176
|
+
storage.removeItem(key);
|
|
177
|
+
};
|
|
178
|
+
|
|
179
|
+
// src/auth/contexts/AuthConfigContext.tsx
|
|
180
|
+
var import_react = require("react");
|
|
181
|
+
var import_jsx_runtime = require("react/jsx-runtime");
|
|
182
|
+
var AuthConfigContext = (0, import_react.createContext)(void 0);
|
|
183
|
+
var AuthConfigProvider = ({ children, config }) => {
|
|
184
|
+
const configWithDefaults = {
|
|
185
|
+
storageType: "localStorage",
|
|
186
|
+
accessTokenKey: "accessToken",
|
|
187
|
+
refreshTokenCookieName: "refreshToken",
|
|
188
|
+
endpoints: {
|
|
189
|
+
refresh: "/refresh",
|
|
190
|
+
logout: "/logout",
|
|
191
|
+
...config.endpoints
|
|
192
|
+
},
|
|
193
|
+
...config
|
|
194
|
+
};
|
|
195
|
+
return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(AuthConfigContext.Provider, { value: { config: configWithDefaults }, children });
|
|
196
|
+
};
|
|
197
|
+
var useAuthConfig = () => {
|
|
198
|
+
const context = (0, import_react.useContext)(AuthConfigContext);
|
|
199
|
+
if (!context) {
|
|
200
|
+
throw new Error("useAuthConfig must be used within an AuthConfigProvider");
|
|
201
|
+
}
|
|
202
|
+
return context.config;
|
|
203
|
+
};
|
|
204
|
+
|
|
205
|
+
// src/auth/contexts/UserContext.tsx
|
|
206
|
+
var import_react2 = require("react");
|
|
207
|
+
var import_jsx_runtime2 = require("react/jsx-runtime");
|
|
208
|
+
var UserContext = (0, import_react2.createContext)(void 0);
|
|
209
|
+
var UserProvider = ({ children }) => {
|
|
210
|
+
const [user, setUser] = (0, import_react2.useState)(null);
|
|
211
|
+
const updateUserFromToken = (0, import_react2.useCallback)((token) => {
|
|
212
|
+
const userInfo = extractUserFromToken(token);
|
|
213
|
+
if (userInfo) {
|
|
214
|
+
setUser(userInfo);
|
|
215
|
+
} else {
|
|
216
|
+
console.warn("Could not extract user information from token");
|
|
217
|
+
setUser(null);
|
|
218
|
+
}
|
|
219
|
+
}, []);
|
|
220
|
+
const clearUser = (0, import_react2.useCallback)(() => {
|
|
221
|
+
setUser(null);
|
|
222
|
+
}, []);
|
|
223
|
+
return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(UserContext.Provider, { value: { user, setUser, updateUserFromToken, clearUser }, children });
|
|
224
|
+
};
|
|
225
|
+
var useUser = () => {
|
|
226
|
+
const context = (0, import_react2.useContext)(UserContext);
|
|
227
|
+
if (!context) {
|
|
228
|
+
throw new Error("useUser must be used within a UserProvider");
|
|
229
|
+
}
|
|
230
|
+
return context;
|
|
231
|
+
};
|
|
232
|
+
|
|
233
|
+
// src/auth/contexts/AuthContext.tsx
|
|
234
|
+
var import_jsx_runtime3 = require("react/jsx-runtime");
|
|
235
|
+
var AuthContext = (0, import_react3.createContext)(void 0);
|
|
236
|
+
var AuthProvider = ({ children }) => {
|
|
237
|
+
const config = useAuthConfig();
|
|
238
|
+
const { updateUserFromToken, clearUser } = useUser();
|
|
239
|
+
const [accessToken, setAccessToken] = (0, import_react3.useState)(() => {
|
|
240
|
+
const stored = getStorageItem(config.accessTokenKey, config.storageType);
|
|
241
|
+
return stored || null;
|
|
242
|
+
});
|
|
243
|
+
(0, import_react3.useEffect)(() => {
|
|
244
|
+
if (accessToken) {
|
|
245
|
+
updateUserFromToken(accessToken);
|
|
246
|
+
} else {
|
|
247
|
+
clearUser();
|
|
248
|
+
}
|
|
249
|
+
}, [accessToken, updateUserFromToken, clearUser]);
|
|
250
|
+
const login = (0, import_react3.useCallback)(
|
|
251
|
+
(token) => {
|
|
252
|
+
setAccessToken(token);
|
|
253
|
+
setStorageItem(config.accessTokenKey, token, config.storageType);
|
|
254
|
+
},
|
|
255
|
+
[config.accessTokenKey, config.storageType]
|
|
256
|
+
);
|
|
257
|
+
const logout = (0, import_react3.useCallback)(async () => {
|
|
258
|
+
try {
|
|
259
|
+
const logoutEndpoint = config.endpoints?.logout || "/logout";
|
|
260
|
+
await fetch(`${config.authUrl}${logoutEndpoint}`, {
|
|
261
|
+
method: "POST",
|
|
262
|
+
credentials: "include"
|
|
263
|
+
});
|
|
264
|
+
} catch (error) {
|
|
265
|
+
console.error("Logout request failed:", error);
|
|
266
|
+
} finally {
|
|
267
|
+
setAccessToken(null);
|
|
268
|
+
removeStorageItem(config.accessTokenKey, config.storageType);
|
|
269
|
+
}
|
|
270
|
+
}, [config.authUrl, config.endpoints?.logout, config.accessTokenKey, config.storageType]);
|
|
271
|
+
const contextValue = (0, import_react3.useMemo)(() => {
|
|
272
|
+
const isAuth = !!accessToken;
|
|
273
|
+
return {
|
|
274
|
+
accessToken,
|
|
275
|
+
isAuthenticated: isAuth,
|
|
276
|
+
login,
|
|
277
|
+
logout
|
|
278
|
+
};
|
|
279
|
+
}, [accessToken, login, logout]);
|
|
280
|
+
return /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(AuthContext.Provider, { value: contextValue, children });
|
|
281
|
+
};
|
|
282
|
+
var useAuth = () => {
|
|
283
|
+
const context = (0, import_react3.useContext)(AuthContext);
|
|
284
|
+
if (!context) {
|
|
285
|
+
throw new Error("useAuth must be used within an AuthProvider");
|
|
286
|
+
}
|
|
287
|
+
return context;
|
|
288
|
+
};
|
|
289
|
+
|
|
290
|
+
// src/auth/components/ProtectedRoute.tsx
|
|
291
|
+
var import_jsx_runtime4 = require("react/jsx-runtime");
|
|
292
|
+
var ProtectedRoute = ({ children, fallbackPath = "/login" }) => {
|
|
293
|
+
const location = (0, import_react_router_dom.useLocation)();
|
|
294
|
+
const { isAuthenticated } = useAuth();
|
|
295
|
+
if (!isAuthenticated) {
|
|
296
|
+
return /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_react_router_dom.Navigate, { to: fallbackPath, state: { from: location }, replace: true });
|
|
297
|
+
}
|
|
298
|
+
return /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_jsx_runtime4.Fragment, { children });
|
|
299
|
+
};
|
|
300
|
+
|
|
301
|
+
// src/auth/hooks/useAuthRedirect.ts
|
|
302
|
+
var import_react4 = require("react");
|
|
303
|
+
var import_react_router_dom2 = require("react-router-dom");
|
|
304
|
+
var useAuthRedirect = (options = {}) => {
|
|
305
|
+
const { redirectTo = "/home", redirectFrom = "/", condition = "authenticated" } = options;
|
|
306
|
+
const navigate = (0, import_react_router_dom2.useNavigate)();
|
|
307
|
+
const location = (0, import_react_router_dom2.useLocation)();
|
|
308
|
+
const { isAuthenticated } = useAuth();
|
|
309
|
+
(0, import_react4.useEffect)(() => {
|
|
310
|
+
const shouldRedirect = condition === "authenticated" ? isAuthenticated && location.pathname === redirectFrom : !isAuthenticated && location.pathname !== redirectFrom;
|
|
311
|
+
if (shouldRedirect) {
|
|
312
|
+
navigate(redirectTo);
|
|
313
|
+
}
|
|
314
|
+
}, [isAuthenticated, navigate, location.pathname, redirectTo, redirectFrom, condition]);
|
|
315
|
+
return { isAuthenticated };
|
|
316
|
+
};
|
|
317
|
+
var useRedirectIfAuthenticated = (to = "/home", from = "/") => {
|
|
318
|
+
return useAuthRedirect({ redirectTo: to, redirectFrom: from, condition: "authenticated" });
|
|
319
|
+
};
|
|
320
|
+
var useRedirectIfUnauthenticated = (to = "/login") => {
|
|
321
|
+
return useAuthRedirect({ redirectTo: to, condition: "unauthenticated" });
|
|
322
|
+
};
|
|
323
|
+
|
|
324
|
+
// src/auth/hooks/useTokenInitialization.ts
|
|
325
|
+
var import_react5 = require("react");
|
|
326
|
+
var useTokenInitialization = () => {
|
|
327
|
+
const { login, isAuthenticated } = useAuth();
|
|
328
|
+
const config = useAuthConfig();
|
|
329
|
+
const [isInitializing, setIsInitializing] = (0, import_react5.useState)(true);
|
|
330
|
+
const initializeToken = (0, import_react5.useCallback)(async () => {
|
|
331
|
+
try {
|
|
332
|
+
const newAccessToken = await tryRefreshToken(config);
|
|
333
|
+
if (newAccessToken) {
|
|
334
|
+
login(newAccessToken);
|
|
335
|
+
}
|
|
336
|
+
} catch {
|
|
337
|
+
removeStorageItem(config.accessTokenKey, config.storageType);
|
|
338
|
+
} finally {
|
|
339
|
+
setIsInitializing(false);
|
|
340
|
+
}
|
|
341
|
+
}, [login, config]);
|
|
342
|
+
(0, import_react5.useEffect)(() => {
|
|
343
|
+
if (!isAuthenticated) {
|
|
344
|
+
initializeToken();
|
|
345
|
+
} else {
|
|
346
|
+
setIsInitializing(false);
|
|
347
|
+
}
|
|
348
|
+
}, [initializeToken, isAuthenticated]);
|
|
349
|
+
return { isInitializing };
|
|
350
|
+
};
|
|
351
|
+
|
|
352
|
+
// src/auth/hooks/useTokenRefresh.ts
|
|
353
|
+
var import_react6 = require("react");
|
|
354
|
+
var useTokenRefresh = () => {
|
|
355
|
+
const { login, logout, accessToken } = useAuth();
|
|
356
|
+
const config = useAuthConfig();
|
|
357
|
+
const refreshPromiseRef = (0, import_react6.useRef)(null);
|
|
358
|
+
const hasRefreshToken = (0, import_react6.useCallback)(() => {
|
|
359
|
+
if (typeof document === "undefined") return false;
|
|
360
|
+
return document.cookie.split(";").some((cookie) => cookie.trim().startsWith(`${config.refreshTokenCookieName}=`));
|
|
361
|
+
}, [config.refreshTokenCookieName]);
|
|
362
|
+
const clearTokens = (0, import_react6.useCallback)(() => {
|
|
363
|
+
logout();
|
|
364
|
+
refreshPromiseRef.current = null;
|
|
365
|
+
clearRefreshTokenCookie(config.refreshTokenCookieName);
|
|
366
|
+
}, [logout, config.refreshTokenCookieName]);
|
|
367
|
+
const performTokenRefresh = (0, import_react6.useCallback)(async () => {
|
|
368
|
+
try {
|
|
369
|
+
const refreshEndpoint = config.endpoints?.refresh || "/refresh";
|
|
370
|
+
const response = await fetch(`${config.authUrl}${refreshEndpoint}`, {
|
|
371
|
+
method: "POST",
|
|
372
|
+
credentials: "include"
|
|
373
|
+
});
|
|
374
|
+
if (!response.ok) {
|
|
375
|
+
if (response.status === 401 || response.status === 403) {
|
|
376
|
+
clearTokens();
|
|
377
|
+
throw new Error("Refresh token expired. Please log in again.");
|
|
378
|
+
} else {
|
|
379
|
+
throw new Error(`Failed to refresh token: ${response.status}`);
|
|
380
|
+
}
|
|
381
|
+
}
|
|
382
|
+
const data = await response.json();
|
|
383
|
+
login(data.accessToken);
|
|
384
|
+
return data.accessToken;
|
|
385
|
+
} catch (error) {
|
|
386
|
+
clearTokens();
|
|
387
|
+
throw error;
|
|
388
|
+
}
|
|
389
|
+
}, [login, clearTokens, config.authUrl, config.endpoints?.refresh]);
|
|
390
|
+
const refreshTokens = (0, import_react6.useCallback)(async () => {
|
|
391
|
+
if (refreshPromiseRef.current) {
|
|
392
|
+
return refreshPromiseRef.current;
|
|
393
|
+
}
|
|
394
|
+
refreshPromiseRef.current = performTokenRefresh();
|
|
395
|
+
try {
|
|
396
|
+
const newAccessToken = await refreshPromiseRef.current;
|
|
397
|
+
refreshPromiseRef.current = null;
|
|
398
|
+
return newAccessToken;
|
|
399
|
+
} catch (error) {
|
|
400
|
+
refreshPromiseRef.current = null;
|
|
401
|
+
throw error;
|
|
402
|
+
}
|
|
403
|
+
}, [performTokenRefresh]);
|
|
404
|
+
const getValidAccessToken = (0, import_react6.useCallback)(async () => {
|
|
405
|
+
if (!accessToken) {
|
|
406
|
+
throw new Error("No access token available. Please log in.");
|
|
407
|
+
}
|
|
408
|
+
return accessToken;
|
|
409
|
+
}, [accessToken]);
|
|
410
|
+
return {
|
|
411
|
+
refreshTokens,
|
|
412
|
+
getValidAccessToken,
|
|
413
|
+
hasRefreshToken,
|
|
414
|
+
clearTokens
|
|
415
|
+
};
|
|
416
|
+
};
|
|
417
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
418
|
+
0 && (module.exports = {
|
|
419
|
+
AuthConfigProvider,
|
|
420
|
+
AuthProvider,
|
|
421
|
+
ProtectedRoute,
|
|
422
|
+
UserProvider,
|
|
423
|
+
clearRefreshTokenCookie,
|
|
424
|
+
decodeJWT,
|
|
425
|
+
extractUserFromToken,
|
|
426
|
+
getStorageItem,
|
|
427
|
+
getTokenExpirationTime,
|
|
428
|
+
isTokenExpired,
|
|
429
|
+
refreshAccessToken,
|
|
430
|
+
removeStorageItem,
|
|
431
|
+
setStorageItem,
|
|
432
|
+
tryRefreshToken,
|
|
433
|
+
useAuth,
|
|
434
|
+
useAuthConfig,
|
|
435
|
+
useAuthRedirect,
|
|
436
|
+
useRedirectIfAuthenticated,
|
|
437
|
+
useRedirectIfUnauthenticated,
|
|
438
|
+
useTokenInitialization,
|
|
439
|
+
useTokenRefresh,
|
|
440
|
+
useUser,
|
|
441
|
+
withTokenRefresh
|
|
442
|
+
});
|
|
443
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/index.ts","../src/auth/components/ProtectedRoute.tsx","../src/auth/contexts/AuthContext.tsx","../src/auth/utils/jwtUtils.ts","../src/auth/utils/tokenUtils.ts","../src/auth/contexts/AuthConfigContext.tsx","../src/auth/contexts/UserContext.tsx","../src/auth/hooks/useAuthRedirect.ts","../src/auth/hooks/useTokenInitialization.ts","../src/auth/hooks/useTokenRefresh.ts"],"sourcesContent":["export * from './auth';\n","import { Navigate, useLocation } from 'react-router-dom';\n\nimport { useAuth } from '../contexts/AuthContext';\nimport type { ProtectedRouteProps } from '../types';\n\nexport const ProtectedRoute = ({ children, fallbackPath = '/login' }: ProtectedRouteProps) => {\n const location = useLocation();\n const { isAuthenticated } = useAuth();\n\n if (!isAuthenticated) {\n return <Navigate to={fallbackPath} state={{ from: location }} replace />;\n }\n\n return <>{children}</>;\n};\n","import { createContext, type ReactNode, useCallback, useContext, useEffect, useMemo, useState } from 'react';\n\nimport type { AuthContextType } from '../types';\nimport { getStorageItem, removeStorageItem, setStorageItem } from '../utils';\nimport { useAuthConfig } from './AuthConfigContext';\nimport { useUser } from './UserContext';\n\nconst AuthContext = createContext<AuthContextType | undefined>(undefined);\n\nexport const AuthProvider = ({ children }: { children: ReactNode }) => {\n const config = useAuthConfig();\n const { updateUserFromToken, clearUser } = useUser();\n\n const [accessToken, setAccessToken] = useState<string | null>(() => {\n const stored = getStorageItem(config.accessTokenKey!, config.storageType);\n\n return stored || null;\n });\n\n useEffect(() => {\n if (accessToken) {\n updateUserFromToken(accessToken);\n } else {\n clearUser();\n }\n }, [accessToken, updateUserFromToken, clearUser]);\n\n const login = useCallback(\n (token: string) => {\n setAccessToken(token);\n setStorageItem(config.accessTokenKey!, token, config.storageType);\n },\n [config.accessTokenKey, config.storageType]\n );\n\n const logout = useCallback(async () => {\n try {\n const logoutEndpoint = config.endpoints?.logout || '/logout';\n\n await fetch(`${config.authUrl}${logoutEndpoint}`, {\n method: 'POST',\n credentials: 'include',\n });\n } catch (error) {\n console.error('Logout request failed:', error);\n } finally {\n setAccessToken(null);\n removeStorageItem(config.accessTokenKey!, config.storageType);\n }\n }, [config.authUrl, config.endpoints?.logout, config.accessTokenKey, config.storageType]);\n\n const contextValue = useMemo(() => {\n const isAuth = !!accessToken;\n\n return {\n accessToken,\n isAuthenticated: isAuth,\n login,\n logout,\n };\n }, [accessToken, login, logout]);\n\n return <AuthContext.Provider value={contextValue}>{children}</AuthContext.Provider>;\n};\n\nexport const useAuth = (): AuthContextType => {\n const context = useContext(AuthContext);\n\n if (!context) {\n throw new Error('useAuth must be used within an AuthProvider');\n }\n\n return context;\n};\n","import type { DecodedToken, UserInfo } from '../types';\n\nexport const decodeJWT = (token: string): DecodedToken | null => {\n try {\n const parts = token.split('.');\n\n if (parts.length !== 3) {\n throw new Error('Invalid JWT token format');\n }\n\n const payload = parts[1];\n\n const paddedPayload = payload + '='.repeat((4 - (payload.length % 4)) % 4);\n\n const decodedPayload = atob(paddedPayload);\n\n const parsedPayload = JSON.parse(decodedPayload);\n\n return parsedPayload as DecodedToken;\n } catch (error) {\n console.error('Failed to decode JWT token:', error);\n\n return null;\n }\n};\n\nexport const isTokenExpired = (token: string): boolean => {\n const decoded = decodeJWT(token);\n\n if (!decoded) {\n return true;\n }\n\n const currentTime = Date.now() / 1000;\n\n return decoded.exp < currentTime;\n};\n\nexport const getTokenExpirationTime = (token: string): Date | null => {\n const decoded = decodeJWT(token);\n\n if (!decoded) {\n return null;\n }\n\n return new Date(decoded.exp * 1000);\n};\n\nexport const extractUserFromToken = (token: string): UserInfo | null => {\n const decoded = decodeJWT(token);\n\n if (!decoded || !decoded.username || !decoded.id) {\n return null;\n }\n\n return {\n username: decoded.username,\n id: decoded.id,\n };\n};\n","import type { AuthConfig, RefreshTokenResponse } from '../types';\n\nexport const tryRefreshToken = async (config: AuthConfig): Promise<string | null> => {\n try {\n const refreshEndpoint = config.endpoints?.refresh || '/refresh';\n const response = await fetch(`${config.authUrl}${refreshEndpoint}`, {\n method: 'POST',\n credentials: 'include',\n });\n\n if (!response.ok) {\n return null;\n }\n\n const data: RefreshTokenResponse = await response.json();\n\n return data.accessToken;\n } catch {\n return null;\n }\n};\n\nexport const clearRefreshTokenCookie = (cookieName = 'refreshToken'): void => {\n document.cookie = `${cookieName}=; expires=Thu, 01 Jan 1970 00:00:00 UTC; path=/;`;\n};\n\nexport const refreshAccessToken = async (config: AuthConfig): Promise<string> => {\n try {\n const refreshEndpoint = config.endpoints?.refresh || '/refresh';\n const response = await fetch(`${config.authUrl}${refreshEndpoint}`, {\n method: 'POST',\n credentials: 'include',\n });\n\n if (!response.ok) {\n if (response.status === 401 || response.status === 403) {\n clearRefreshTokenCookie(config.refreshTokenCookieName);\n throw new Error('Refresh token expired. Please log in again.');\n } else {\n throw new Error(`Failed to refresh token: ${response.status}`);\n }\n }\n\n const data: RefreshTokenResponse = await response.json();\n\n return data.accessToken;\n } catch (error) {\n clearRefreshTokenCookie(config.refreshTokenCookieName);\n throw error;\n }\n};\n\nexport const withTokenRefresh = async <T>(\n requestFn: () => Promise<T>,\n onTokenRefresh: (newToken: string) => void,\n onTokenClear: () => void,\n config: AuthConfig\n): Promise<T> => {\n try {\n return await requestFn();\n } catch (error) {\n if (error instanceof Error && error.message.includes('401')) {\n try {\n const newAccessToken = await tryRefreshToken(config);\n\n if (newAccessToken) {\n onTokenRefresh(newAccessToken);\n\n return await requestFn();\n } else {\n onTokenClear();\n clearRefreshTokenCookie(config.refreshTokenCookieName);\n throw new Error('No valid refresh token available');\n }\n } catch (refreshError) {\n onTokenClear();\n clearRefreshTokenCookie(config.refreshTokenCookieName);\n throw refreshError;\n }\n }\n\n throw error;\n }\n};\n\nexport const getStorageItem = (\n key: string,\n storageType: 'localStorage' | 'sessionStorage' = 'localStorage'\n): string | null => {\n if (typeof window === 'undefined') return null;\n\n const storage = storageType === 'localStorage' ? window.localStorage : window.sessionStorage;\n\n return storage.getItem(key);\n};\n\nexport const setStorageItem = (\n key: string,\n value: string,\n storageType: 'localStorage' | 'sessionStorage' = 'localStorage'\n): void => {\n if (typeof window === 'undefined') return;\n\n const storage = storageType === 'localStorage' ? window.localStorage : window.sessionStorage;\n\n storage.setItem(key, value);\n};\n\nexport const removeStorageItem = (\n key: string,\n storageType: 'localStorage' | 'sessionStorage' = 'localStorage'\n): void => {\n if (typeof window === 'undefined') return;\n\n const storage = storageType === 'localStorage' ? window.localStorage : window.sessionStorage;\n\n storage.removeItem(key);\n};\n","import { createContext, type ReactNode, useContext } from 'react';\n\nimport type { AuthConfig } from '../types';\n\ninterface AuthConfigContextType {\n config: AuthConfig;\n}\n\nconst AuthConfigContext = createContext<AuthConfigContextType | undefined>(undefined);\n\ninterface AuthConfigProviderProps {\n children: ReactNode;\n config: AuthConfig;\n}\n\nexport const AuthConfigProvider = ({ children, config }: AuthConfigProviderProps) => {\n const configWithDefaults: AuthConfig = {\n storageType: 'localStorage',\n accessTokenKey: 'accessToken',\n refreshTokenCookieName: 'refreshToken',\n endpoints: {\n refresh: '/refresh',\n logout: '/logout',\n ...config.endpoints,\n },\n ...config,\n };\n\n return <AuthConfigContext.Provider value={{ config: configWithDefaults }}>{children}</AuthConfigContext.Provider>;\n};\n\nexport const useAuthConfig = (): AuthConfig => {\n const context = useContext(AuthConfigContext);\n\n if (!context) {\n throw new Error('useAuthConfig must be used within an AuthConfigProvider');\n }\n\n return context.config;\n};\n","import { createContext, type ReactNode, useCallback, useContext, useState } from 'react';\n\nimport type { UserContextType, UserInfo } from '../types';\nimport { extractUserFromToken } from '../utils';\n\nconst UserContext = createContext<UserContextType | undefined>(undefined);\n\nexport const UserProvider = ({ children }: { children: ReactNode }) => {\n const [user, setUser] = useState<UserInfo | null>(null);\n\n const updateUserFromToken = useCallback((token: string) => {\n const userInfo = extractUserFromToken(token);\n\n if (userInfo) {\n setUser(userInfo);\n } else {\n console.warn('Could not extract user information from token');\n setUser(null);\n }\n }, []);\n\n const clearUser = useCallback(() => {\n setUser(null);\n }, []);\n\n return (\n <UserContext.Provider value={{ user, setUser, updateUserFromToken, clearUser }}>\n {children}\n </UserContext.Provider>\n );\n};\n\nexport const useUser = (): UserContextType => {\n const context = useContext(UserContext);\n\n if (!context) {\n throw new Error('useUser must be used within a UserProvider');\n }\n\n return context;\n};\n","import { useEffect } from 'react';\nimport { useLocation, useNavigate } from 'react-router-dom';\n\nimport { useAuth } from '../contexts/AuthContext';\nimport type { UseAuthRedirectOptions } from '../types';\n\nexport const useAuthRedirect = (options: UseAuthRedirectOptions = {}) => {\n const { redirectTo = '/home', redirectFrom = '/', condition = 'authenticated' } = options;\n\n const navigate = useNavigate();\n const location = useLocation();\n const { isAuthenticated } = useAuth();\n\n useEffect(() => {\n const shouldRedirect =\n condition === 'authenticated'\n ? isAuthenticated && location.pathname === redirectFrom\n : !isAuthenticated && location.pathname !== redirectFrom;\n\n if (shouldRedirect) {\n navigate(redirectTo);\n }\n }, [isAuthenticated, navigate, location.pathname, redirectTo, redirectFrom, condition]);\n\n return { isAuthenticated };\n};\n\nexport const useRedirectIfAuthenticated = (to = '/home', from = '/') => {\n return useAuthRedirect({ redirectTo: to, redirectFrom: from, condition: 'authenticated' });\n};\n\nexport const useRedirectIfUnauthenticated = (to = '/login') => {\n return useAuthRedirect({ redirectTo: to, condition: 'unauthenticated' });\n};\n","import { useCallback, useEffect, useState } from 'react';\n\nimport { useAuthConfig } from '../contexts/AuthConfigContext';\nimport { useAuth } from '../contexts/AuthContext';\nimport { removeStorageItem, tryRefreshToken } from '../utils';\n\nexport const useTokenInitialization = () => {\n const { login, isAuthenticated } = useAuth();\n const config = useAuthConfig();\n const [isInitializing, setIsInitializing] = useState(true);\n\n const initializeToken = useCallback(async () => {\n try {\n const newAccessToken = await tryRefreshToken(config);\n\n if (newAccessToken) {\n login(newAccessToken);\n }\n } catch {\n removeStorageItem(config.accessTokenKey!, config.storageType);\n } finally {\n setIsInitializing(false);\n }\n }, [login, config]);\n\n useEffect(() => {\n if (!isAuthenticated) {\n initializeToken();\n } else {\n setIsInitializing(false);\n }\n }, [initializeToken, isAuthenticated]);\n\n return { isInitializing };\n};\n","import { useCallback, useRef } from 'react';\n\nimport { useAuthConfig } from '../contexts/AuthConfigContext';\nimport { useAuth } from '../contexts/AuthContext';\nimport type { RefreshTokenResponse } from '../types';\nimport { clearRefreshTokenCookie } from '../utils';\n\nexport const useTokenRefresh = () => {\n const { login, logout, accessToken } = useAuth();\n const config = useAuthConfig();\n const refreshPromiseRef = useRef<Promise<string> | null>(null);\n\n const hasRefreshToken = useCallback((): boolean => {\n if (typeof document === 'undefined') return false;\n\n return document.cookie\n .split(';')\n .some((cookie) => cookie.trim().startsWith(`${config.refreshTokenCookieName}=`));\n }, [config.refreshTokenCookieName]);\n\n const clearTokens = useCallback(() => {\n logout();\n refreshPromiseRef.current = null;\n clearRefreshTokenCookie(config.refreshTokenCookieName);\n }, [logout, config.refreshTokenCookieName]);\n\n const performTokenRefresh = useCallback(async (): Promise<string> => {\n try {\n const refreshEndpoint = config.endpoints?.refresh || '/refresh';\n const response = await fetch(`${config.authUrl}${refreshEndpoint}`, {\n method: 'POST',\n credentials: 'include',\n });\n\n if (!response.ok) {\n if (response.status === 401 || response.status === 403) {\n clearTokens();\n throw new Error('Refresh token expired. Please log in again.');\n } else {\n throw new Error(`Failed to refresh token: ${response.status}`);\n }\n }\n\n const data: RefreshTokenResponse = await response.json();\n\n login(data.accessToken);\n\n return data.accessToken;\n } catch (error) {\n clearTokens();\n throw error;\n }\n }, [login, clearTokens, config.authUrl, config.endpoints?.refresh]);\n\n const refreshTokens = useCallback(async (): Promise<string> => {\n if (refreshPromiseRef.current) {\n return refreshPromiseRef.current;\n }\n\n refreshPromiseRef.current = performTokenRefresh();\n\n try {\n const newAccessToken = await refreshPromiseRef.current;\n\n refreshPromiseRef.current = null;\n\n return newAccessToken;\n } catch (error) {\n refreshPromiseRef.current = null;\n throw error;\n }\n }, [performTokenRefresh]);\n\n const getValidAccessToken = useCallback(async (): Promise<string> => {\n if (!accessToken) {\n throw new Error('No access token available. Please log in.');\n }\n\n return accessToken;\n }, [accessToken]);\n\n return {\n refreshTokens,\n getValidAccessToken,\n hasRefreshToken,\n clearTokens,\n };\n};\n"],"mappings":"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","names":["import_react","import_react","import_jsx_runtime","import_jsx_runtime","import_jsx_runtime","import_react","import_react_router_dom","import_react","import_react"]}
|
package/build/index.mjs
ADDED
|
@@ -0,0 +1,395 @@
|
|
|
1
|
+
// src/auth/components/ProtectedRoute.tsx
|
|
2
|
+
import { Navigate, useLocation } from "react-router-dom";
|
|
3
|
+
|
|
4
|
+
// src/auth/contexts/AuthContext.tsx
|
|
5
|
+
import { createContext as createContext3, useCallback as useCallback2, useContext as useContext3, useEffect, useMemo, useState as useState2 } from "react";
|
|
6
|
+
|
|
7
|
+
// src/auth/utils/jwtUtils.ts
|
|
8
|
+
var decodeJWT = (token) => {
|
|
9
|
+
try {
|
|
10
|
+
const parts = token.split(".");
|
|
11
|
+
if (parts.length !== 3) {
|
|
12
|
+
throw new Error("Invalid JWT token format");
|
|
13
|
+
}
|
|
14
|
+
const payload = parts[1];
|
|
15
|
+
const paddedPayload = payload + "=".repeat((4 - payload.length % 4) % 4);
|
|
16
|
+
const decodedPayload = atob(paddedPayload);
|
|
17
|
+
const parsedPayload = JSON.parse(decodedPayload);
|
|
18
|
+
return parsedPayload;
|
|
19
|
+
} catch (error) {
|
|
20
|
+
console.error("Failed to decode JWT token:", error);
|
|
21
|
+
return null;
|
|
22
|
+
}
|
|
23
|
+
};
|
|
24
|
+
var isTokenExpired = (token) => {
|
|
25
|
+
const decoded = decodeJWT(token);
|
|
26
|
+
if (!decoded) {
|
|
27
|
+
return true;
|
|
28
|
+
}
|
|
29
|
+
const currentTime = Date.now() / 1e3;
|
|
30
|
+
return decoded.exp < currentTime;
|
|
31
|
+
};
|
|
32
|
+
var getTokenExpirationTime = (token) => {
|
|
33
|
+
const decoded = decodeJWT(token);
|
|
34
|
+
if (!decoded) {
|
|
35
|
+
return null;
|
|
36
|
+
}
|
|
37
|
+
return new Date(decoded.exp * 1e3);
|
|
38
|
+
};
|
|
39
|
+
var extractUserFromToken = (token) => {
|
|
40
|
+
const decoded = decodeJWT(token);
|
|
41
|
+
if (!decoded || !decoded.username || !decoded.id) {
|
|
42
|
+
return null;
|
|
43
|
+
}
|
|
44
|
+
return {
|
|
45
|
+
username: decoded.username,
|
|
46
|
+
id: decoded.id
|
|
47
|
+
};
|
|
48
|
+
};
|
|
49
|
+
|
|
50
|
+
// src/auth/utils/tokenUtils.ts
|
|
51
|
+
var tryRefreshToken = async (config) => {
|
|
52
|
+
try {
|
|
53
|
+
const refreshEndpoint = config.endpoints?.refresh || "/refresh";
|
|
54
|
+
const response = await fetch(`${config.authUrl}${refreshEndpoint}`, {
|
|
55
|
+
method: "POST",
|
|
56
|
+
credentials: "include"
|
|
57
|
+
});
|
|
58
|
+
if (!response.ok) {
|
|
59
|
+
return null;
|
|
60
|
+
}
|
|
61
|
+
const data = await response.json();
|
|
62
|
+
return data.accessToken;
|
|
63
|
+
} catch {
|
|
64
|
+
return null;
|
|
65
|
+
}
|
|
66
|
+
};
|
|
67
|
+
var clearRefreshTokenCookie = (cookieName = "refreshToken") => {
|
|
68
|
+
document.cookie = `${cookieName}=; expires=Thu, 01 Jan 1970 00:00:00 UTC; path=/;`;
|
|
69
|
+
};
|
|
70
|
+
var refreshAccessToken = async (config) => {
|
|
71
|
+
try {
|
|
72
|
+
const refreshEndpoint = config.endpoints?.refresh || "/refresh";
|
|
73
|
+
const response = await fetch(`${config.authUrl}${refreshEndpoint}`, {
|
|
74
|
+
method: "POST",
|
|
75
|
+
credentials: "include"
|
|
76
|
+
});
|
|
77
|
+
if (!response.ok) {
|
|
78
|
+
if (response.status === 401 || response.status === 403) {
|
|
79
|
+
clearRefreshTokenCookie(config.refreshTokenCookieName);
|
|
80
|
+
throw new Error("Refresh token expired. Please log in again.");
|
|
81
|
+
} else {
|
|
82
|
+
throw new Error(`Failed to refresh token: ${response.status}`);
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
const data = await response.json();
|
|
86
|
+
return data.accessToken;
|
|
87
|
+
} catch (error) {
|
|
88
|
+
clearRefreshTokenCookie(config.refreshTokenCookieName);
|
|
89
|
+
throw error;
|
|
90
|
+
}
|
|
91
|
+
};
|
|
92
|
+
var withTokenRefresh = async (requestFn, onTokenRefresh, onTokenClear, config) => {
|
|
93
|
+
try {
|
|
94
|
+
return await requestFn();
|
|
95
|
+
} catch (error) {
|
|
96
|
+
if (error instanceof Error && error.message.includes("401")) {
|
|
97
|
+
try {
|
|
98
|
+
const newAccessToken = await tryRefreshToken(config);
|
|
99
|
+
if (newAccessToken) {
|
|
100
|
+
onTokenRefresh(newAccessToken);
|
|
101
|
+
return await requestFn();
|
|
102
|
+
} else {
|
|
103
|
+
onTokenClear();
|
|
104
|
+
clearRefreshTokenCookie(config.refreshTokenCookieName);
|
|
105
|
+
throw new Error("No valid refresh token available");
|
|
106
|
+
}
|
|
107
|
+
} catch (refreshError) {
|
|
108
|
+
onTokenClear();
|
|
109
|
+
clearRefreshTokenCookie(config.refreshTokenCookieName);
|
|
110
|
+
throw refreshError;
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
throw error;
|
|
114
|
+
}
|
|
115
|
+
};
|
|
116
|
+
var getStorageItem = (key, storageType = "localStorage") => {
|
|
117
|
+
if (typeof window === "undefined") return null;
|
|
118
|
+
const storage = storageType === "localStorage" ? window.localStorage : window.sessionStorage;
|
|
119
|
+
return storage.getItem(key);
|
|
120
|
+
};
|
|
121
|
+
var setStorageItem = (key, value, storageType = "localStorage") => {
|
|
122
|
+
if (typeof window === "undefined") return;
|
|
123
|
+
const storage = storageType === "localStorage" ? window.localStorage : window.sessionStorage;
|
|
124
|
+
storage.setItem(key, value);
|
|
125
|
+
};
|
|
126
|
+
var removeStorageItem = (key, storageType = "localStorage") => {
|
|
127
|
+
if (typeof window === "undefined") return;
|
|
128
|
+
const storage = storageType === "localStorage" ? window.localStorage : window.sessionStorage;
|
|
129
|
+
storage.removeItem(key);
|
|
130
|
+
};
|
|
131
|
+
|
|
132
|
+
// src/auth/contexts/AuthConfigContext.tsx
|
|
133
|
+
import { createContext, useContext } from "react";
|
|
134
|
+
import { jsx } from "react/jsx-runtime";
|
|
135
|
+
var AuthConfigContext = createContext(void 0);
|
|
136
|
+
var AuthConfigProvider = ({ children, config }) => {
|
|
137
|
+
const configWithDefaults = {
|
|
138
|
+
storageType: "localStorage",
|
|
139
|
+
accessTokenKey: "accessToken",
|
|
140
|
+
refreshTokenCookieName: "refreshToken",
|
|
141
|
+
endpoints: {
|
|
142
|
+
refresh: "/refresh",
|
|
143
|
+
logout: "/logout",
|
|
144
|
+
...config.endpoints
|
|
145
|
+
},
|
|
146
|
+
...config
|
|
147
|
+
};
|
|
148
|
+
return /* @__PURE__ */ jsx(AuthConfigContext.Provider, { value: { config: configWithDefaults }, children });
|
|
149
|
+
};
|
|
150
|
+
var useAuthConfig = () => {
|
|
151
|
+
const context = useContext(AuthConfigContext);
|
|
152
|
+
if (!context) {
|
|
153
|
+
throw new Error("useAuthConfig must be used within an AuthConfigProvider");
|
|
154
|
+
}
|
|
155
|
+
return context.config;
|
|
156
|
+
};
|
|
157
|
+
|
|
158
|
+
// src/auth/contexts/UserContext.tsx
|
|
159
|
+
import { createContext as createContext2, useCallback, useContext as useContext2, useState } from "react";
|
|
160
|
+
import { jsx as jsx2 } from "react/jsx-runtime";
|
|
161
|
+
var UserContext = createContext2(void 0);
|
|
162
|
+
var UserProvider = ({ children }) => {
|
|
163
|
+
const [user, setUser] = useState(null);
|
|
164
|
+
const updateUserFromToken = useCallback((token) => {
|
|
165
|
+
const userInfo = extractUserFromToken(token);
|
|
166
|
+
if (userInfo) {
|
|
167
|
+
setUser(userInfo);
|
|
168
|
+
} else {
|
|
169
|
+
console.warn("Could not extract user information from token");
|
|
170
|
+
setUser(null);
|
|
171
|
+
}
|
|
172
|
+
}, []);
|
|
173
|
+
const clearUser = useCallback(() => {
|
|
174
|
+
setUser(null);
|
|
175
|
+
}, []);
|
|
176
|
+
return /* @__PURE__ */ jsx2(UserContext.Provider, { value: { user, setUser, updateUserFromToken, clearUser }, children });
|
|
177
|
+
};
|
|
178
|
+
var useUser = () => {
|
|
179
|
+
const context = useContext2(UserContext);
|
|
180
|
+
if (!context) {
|
|
181
|
+
throw new Error("useUser must be used within a UserProvider");
|
|
182
|
+
}
|
|
183
|
+
return context;
|
|
184
|
+
};
|
|
185
|
+
|
|
186
|
+
// src/auth/contexts/AuthContext.tsx
|
|
187
|
+
import { jsx as jsx3 } from "react/jsx-runtime";
|
|
188
|
+
var AuthContext = createContext3(void 0);
|
|
189
|
+
var AuthProvider = ({ children }) => {
|
|
190
|
+
const config = useAuthConfig();
|
|
191
|
+
const { updateUserFromToken, clearUser } = useUser();
|
|
192
|
+
const [accessToken, setAccessToken] = useState2(() => {
|
|
193
|
+
const stored = getStorageItem(config.accessTokenKey, config.storageType);
|
|
194
|
+
return stored || null;
|
|
195
|
+
});
|
|
196
|
+
useEffect(() => {
|
|
197
|
+
if (accessToken) {
|
|
198
|
+
updateUserFromToken(accessToken);
|
|
199
|
+
} else {
|
|
200
|
+
clearUser();
|
|
201
|
+
}
|
|
202
|
+
}, [accessToken, updateUserFromToken, clearUser]);
|
|
203
|
+
const login = useCallback2(
|
|
204
|
+
(token) => {
|
|
205
|
+
setAccessToken(token);
|
|
206
|
+
setStorageItem(config.accessTokenKey, token, config.storageType);
|
|
207
|
+
},
|
|
208
|
+
[config.accessTokenKey, config.storageType]
|
|
209
|
+
);
|
|
210
|
+
const logout = useCallback2(async () => {
|
|
211
|
+
try {
|
|
212
|
+
const logoutEndpoint = config.endpoints?.logout || "/logout";
|
|
213
|
+
await fetch(`${config.authUrl}${logoutEndpoint}`, {
|
|
214
|
+
method: "POST",
|
|
215
|
+
credentials: "include"
|
|
216
|
+
});
|
|
217
|
+
} catch (error) {
|
|
218
|
+
console.error("Logout request failed:", error);
|
|
219
|
+
} finally {
|
|
220
|
+
setAccessToken(null);
|
|
221
|
+
removeStorageItem(config.accessTokenKey, config.storageType);
|
|
222
|
+
}
|
|
223
|
+
}, [config.authUrl, config.endpoints?.logout, config.accessTokenKey, config.storageType]);
|
|
224
|
+
const contextValue = useMemo(() => {
|
|
225
|
+
const isAuth = !!accessToken;
|
|
226
|
+
return {
|
|
227
|
+
accessToken,
|
|
228
|
+
isAuthenticated: isAuth,
|
|
229
|
+
login,
|
|
230
|
+
logout
|
|
231
|
+
};
|
|
232
|
+
}, [accessToken, login, logout]);
|
|
233
|
+
return /* @__PURE__ */ jsx3(AuthContext.Provider, { value: contextValue, children });
|
|
234
|
+
};
|
|
235
|
+
var useAuth = () => {
|
|
236
|
+
const context = useContext3(AuthContext);
|
|
237
|
+
if (!context) {
|
|
238
|
+
throw new Error("useAuth must be used within an AuthProvider");
|
|
239
|
+
}
|
|
240
|
+
return context;
|
|
241
|
+
};
|
|
242
|
+
|
|
243
|
+
// src/auth/components/ProtectedRoute.tsx
|
|
244
|
+
import { Fragment, jsx as jsx4 } from "react/jsx-runtime";
|
|
245
|
+
var ProtectedRoute = ({ children, fallbackPath = "/login" }) => {
|
|
246
|
+
const location = useLocation();
|
|
247
|
+
const { isAuthenticated } = useAuth();
|
|
248
|
+
if (!isAuthenticated) {
|
|
249
|
+
return /* @__PURE__ */ jsx4(Navigate, { to: fallbackPath, state: { from: location }, replace: true });
|
|
250
|
+
}
|
|
251
|
+
return /* @__PURE__ */ jsx4(Fragment, { children });
|
|
252
|
+
};
|
|
253
|
+
|
|
254
|
+
// src/auth/hooks/useAuthRedirect.ts
|
|
255
|
+
import { useEffect as useEffect2 } from "react";
|
|
256
|
+
import { useLocation as useLocation2, useNavigate } from "react-router-dom";
|
|
257
|
+
var useAuthRedirect = (options = {}) => {
|
|
258
|
+
const { redirectTo = "/home", redirectFrom = "/", condition = "authenticated" } = options;
|
|
259
|
+
const navigate = useNavigate();
|
|
260
|
+
const location = useLocation2();
|
|
261
|
+
const { isAuthenticated } = useAuth();
|
|
262
|
+
useEffect2(() => {
|
|
263
|
+
const shouldRedirect = condition === "authenticated" ? isAuthenticated && location.pathname === redirectFrom : !isAuthenticated && location.pathname !== redirectFrom;
|
|
264
|
+
if (shouldRedirect) {
|
|
265
|
+
navigate(redirectTo);
|
|
266
|
+
}
|
|
267
|
+
}, [isAuthenticated, navigate, location.pathname, redirectTo, redirectFrom, condition]);
|
|
268
|
+
return { isAuthenticated };
|
|
269
|
+
};
|
|
270
|
+
var useRedirectIfAuthenticated = (to = "/home", from = "/") => {
|
|
271
|
+
return useAuthRedirect({ redirectTo: to, redirectFrom: from, condition: "authenticated" });
|
|
272
|
+
};
|
|
273
|
+
var useRedirectIfUnauthenticated = (to = "/login") => {
|
|
274
|
+
return useAuthRedirect({ redirectTo: to, condition: "unauthenticated" });
|
|
275
|
+
};
|
|
276
|
+
|
|
277
|
+
// src/auth/hooks/useTokenInitialization.ts
|
|
278
|
+
import { useCallback as useCallback3, useEffect as useEffect3, useState as useState3 } from "react";
|
|
279
|
+
var useTokenInitialization = () => {
|
|
280
|
+
const { login, isAuthenticated } = useAuth();
|
|
281
|
+
const config = useAuthConfig();
|
|
282
|
+
const [isInitializing, setIsInitializing] = useState3(true);
|
|
283
|
+
const initializeToken = useCallback3(async () => {
|
|
284
|
+
try {
|
|
285
|
+
const newAccessToken = await tryRefreshToken(config);
|
|
286
|
+
if (newAccessToken) {
|
|
287
|
+
login(newAccessToken);
|
|
288
|
+
}
|
|
289
|
+
} catch {
|
|
290
|
+
removeStorageItem(config.accessTokenKey, config.storageType);
|
|
291
|
+
} finally {
|
|
292
|
+
setIsInitializing(false);
|
|
293
|
+
}
|
|
294
|
+
}, [login, config]);
|
|
295
|
+
useEffect3(() => {
|
|
296
|
+
if (!isAuthenticated) {
|
|
297
|
+
initializeToken();
|
|
298
|
+
} else {
|
|
299
|
+
setIsInitializing(false);
|
|
300
|
+
}
|
|
301
|
+
}, [initializeToken, isAuthenticated]);
|
|
302
|
+
return { isInitializing };
|
|
303
|
+
};
|
|
304
|
+
|
|
305
|
+
// src/auth/hooks/useTokenRefresh.ts
|
|
306
|
+
import { useCallback as useCallback4, useRef } from "react";
|
|
307
|
+
var useTokenRefresh = () => {
|
|
308
|
+
const { login, logout, accessToken } = useAuth();
|
|
309
|
+
const config = useAuthConfig();
|
|
310
|
+
const refreshPromiseRef = useRef(null);
|
|
311
|
+
const hasRefreshToken = useCallback4(() => {
|
|
312
|
+
if (typeof document === "undefined") return false;
|
|
313
|
+
return document.cookie.split(";").some((cookie) => cookie.trim().startsWith(`${config.refreshTokenCookieName}=`));
|
|
314
|
+
}, [config.refreshTokenCookieName]);
|
|
315
|
+
const clearTokens = useCallback4(() => {
|
|
316
|
+
logout();
|
|
317
|
+
refreshPromiseRef.current = null;
|
|
318
|
+
clearRefreshTokenCookie(config.refreshTokenCookieName);
|
|
319
|
+
}, [logout, config.refreshTokenCookieName]);
|
|
320
|
+
const performTokenRefresh = useCallback4(async () => {
|
|
321
|
+
try {
|
|
322
|
+
const refreshEndpoint = config.endpoints?.refresh || "/refresh";
|
|
323
|
+
const response = await fetch(`${config.authUrl}${refreshEndpoint}`, {
|
|
324
|
+
method: "POST",
|
|
325
|
+
credentials: "include"
|
|
326
|
+
});
|
|
327
|
+
if (!response.ok) {
|
|
328
|
+
if (response.status === 401 || response.status === 403) {
|
|
329
|
+
clearTokens();
|
|
330
|
+
throw new Error("Refresh token expired. Please log in again.");
|
|
331
|
+
} else {
|
|
332
|
+
throw new Error(`Failed to refresh token: ${response.status}`);
|
|
333
|
+
}
|
|
334
|
+
}
|
|
335
|
+
const data = await response.json();
|
|
336
|
+
login(data.accessToken);
|
|
337
|
+
return data.accessToken;
|
|
338
|
+
} catch (error) {
|
|
339
|
+
clearTokens();
|
|
340
|
+
throw error;
|
|
341
|
+
}
|
|
342
|
+
}, [login, clearTokens, config.authUrl, config.endpoints?.refresh]);
|
|
343
|
+
const refreshTokens = useCallback4(async () => {
|
|
344
|
+
if (refreshPromiseRef.current) {
|
|
345
|
+
return refreshPromiseRef.current;
|
|
346
|
+
}
|
|
347
|
+
refreshPromiseRef.current = performTokenRefresh();
|
|
348
|
+
try {
|
|
349
|
+
const newAccessToken = await refreshPromiseRef.current;
|
|
350
|
+
refreshPromiseRef.current = null;
|
|
351
|
+
return newAccessToken;
|
|
352
|
+
} catch (error) {
|
|
353
|
+
refreshPromiseRef.current = null;
|
|
354
|
+
throw error;
|
|
355
|
+
}
|
|
356
|
+
}, [performTokenRefresh]);
|
|
357
|
+
const getValidAccessToken = useCallback4(async () => {
|
|
358
|
+
if (!accessToken) {
|
|
359
|
+
throw new Error("No access token available. Please log in.");
|
|
360
|
+
}
|
|
361
|
+
return accessToken;
|
|
362
|
+
}, [accessToken]);
|
|
363
|
+
return {
|
|
364
|
+
refreshTokens,
|
|
365
|
+
getValidAccessToken,
|
|
366
|
+
hasRefreshToken,
|
|
367
|
+
clearTokens
|
|
368
|
+
};
|
|
369
|
+
};
|
|
370
|
+
export {
|
|
371
|
+
AuthConfigProvider,
|
|
372
|
+
AuthProvider,
|
|
373
|
+
ProtectedRoute,
|
|
374
|
+
UserProvider,
|
|
375
|
+
clearRefreshTokenCookie,
|
|
376
|
+
decodeJWT,
|
|
377
|
+
extractUserFromToken,
|
|
378
|
+
getStorageItem,
|
|
379
|
+
getTokenExpirationTime,
|
|
380
|
+
isTokenExpired,
|
|
381
|
+
refreshAccessToken,
|
|
382
|
+
removeStorageItem,
|
|
383
|
+
setStorageItem,
|
|
384
|
+
tryRefreshToken,
|
|
385
|
+
useAuth,
|
|
386
|
+
useAuthConfig,
|
|
387
|
+
useAuthRedirect,
|
|
388
|
+
useRedirectIfAuthenticated,
|
|
389
|
+
useRedirectIfUnauthenticated,
|
|
390
|
+
useTokenInitialization,
|
|
391
|
+
useTokenRefresh,
|
|
392
|
+
useUser,
|
|
393
|
+
withTokenRefresh
|
|
394
|
+
};
|
|
395
|
+
//# sourceMappingURL=index.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/auth/components/ProtectedRoute.tsx","../src/auth/contexts/AuthContext.tsx","../src/auth/utils/jwtUtils.ts","../src/auth/utils/tokenUtils.ts","../src/auth/contexts/AuthConfigContext.tsx","../src/auth/contexts/UserContext.tsx","../src/auth/hooks/useAuthRedirect.ts","../src/auth/hooks/useTokenInitialization.ts","../src/auth/hooks/useTokenRefresh.ts"],"sourcesContent":["import { Navigate, useLocation } from 'react-router-dom';\n\nimport { useAuth } from '../contexts/AuthContext';\nimport type { ProtectedRouteProps } from '../types';\n\nexport const ProtectedRoute = ({ children, fallbackPath = '/login' }: ProtectedRouteProps) => {\n const location = useLocation();\n const { isAuthenticated } = useAuth();\n\n if (!isAuthenticated) {\n return <Navigate to={fallbackPath} state={{ from: location }} replace />;\n }\n\n return <>{children}</>;\n};\n","import { createContext, type ReactNode, useCallback, useContext, useEffect, useMemo, useState } from 'react';\n\nimport type { AuthContextType } from '../types';\nimport { getStorageItem, removeStorageItem, setStorageItem } from '../utils';\nimport { useAuthConfig } from './AuthConfigContext';\nimport { useUser } from './UserContext';\n\nconst AuthContext = createContext<AuthContextType | undefined>(undefined);\n\nexport const AuthProvider = ({ children }: { children: ReactNode }) => {\n const config = useAuthConfig();\n const { updateUserFromToken, clearUser } = useUser();\n\n const [accessToken, setAccessToken] = useState<string | null>(() => {\n const stored = getStorageItem(config.accessTokenKey!, config.storageType);\n\n return stored || null;\n });\n\n useEffect(() => {\n if (accessToken) {\n updateUserFromToken(accessToken);\n } else {\n clearUser();\n }\n }, [accessToken, updateUserFromToken, clearUser]);\n\n const login = useCallback(\n (token: string) => {\n setAccessToken(token);\n setStorageItem(config.accessTokenKey!, token, config.storageType);\n },\n [config.accessTokenKey, config.storageType]\n );\n\n const logout = useCallback(async () => {\n try {\n const logoutEndpoint = config.endpoints?.logout || '/logout';\n\n await fetch(`${config.authUrl}${logoutEndpoint}`, {\n method: 'POST',\n credentials: 'include',\n });\n } catch (error) {\n console.error('Logout request failed:', error);\n } finally {\n setAccessToken(null);\n removeStorageItem(config.accessTokenKey!, config.storageType);\n }\n }, [config.authUrl, config.endpoints?.logout, config.accessTokenKey, config.storageType]);\n\n const contextValue = useMemo(() => {\n const isAuth = !!accessToken;\n\n return {\n accessToken,\n isAuthenticated: isAuth,\n login,\n logout,\n };\n }, [accessToken, login, logout]);\n\n return <AuthContext.Provider value={contextValue}>{children}</AuthContext.Provider>;\n};\n\nexport const useAuth = (): AuthContextType => {\n const context = useContext(AuthContext);\n\n if (!context) {\n throw new Error('useAuth must be used within an AuthProvider');\n }\n\n return context;\n};\n","import type { DecodedToken, UserInfo } from '../types';\n\nexport const decodeJWT = (token: string): DecodedToken | null => {\n try {\n const parts = token.split('.');\n\n if (parts.length !== 3) {\n throw new Error('Invalid JWT token format');\n }\n\n const payload = parts[1];\n\n const paddedPayload = payload + '='.repeat((4 - (payload.length % 4)) % 4);\n\n const decodedPayload = atob(paddedPayload);\n\n const parsedPayload = JSON.parse(decodedPayload);\n\n return parsedPayload as DecodedToken;\n } catch (error) {\n console.error('Failed to decode JWT token:', error);\n\n return null;\n }\n};\n\nexport const isTokenExpired = (token: string): boolean => {\n const decoded = decodeJWT(token);\n\n if (!decoded) {\n return true;\n }\n\n const currentTime = Date.now() / 1000;\n\n return decoded.exp < currentTime;\n};\n\nexport const getTokenExpirationTime = (token: string): Date | null => {\n const decoded = decodeJWT(token);\n\n if (!decoded) {\n return null;\n }\n\n return new Date(decoded.exp * 1000);\n};\n\nexport const extractUserFromToken = (token: string): UserInfo | null => {\n const decoded = decodeJWT(token);\n\n if (!decoded || !decoded.username || !decoded.id) {\n return null;\n }\n\n return {\n username: decoded.username,\n id: decoded.id,\n };\n};\n","import type { AuthConfig, RefreshTokenResponse } from '../types';\n\nexport const tryRefreshToken = async (config: AuthConfig): Promise<string | null> => {\n try {\n const refreshEndpoint = config.endpoints?.refresh || '/refresh';\n const response = await fetch(`${config.authUrl}${refreshEndpoint}`, {\n method: 'POST',\n credentials: 'include',\n });\n\n if (!response.ok) {\n return null;\n }\n\n const data: RefreshTokenResponse = await response.json();\n\n return data.accessToken;\n } catch {\n return null;\n }\n};\n\nexport const clearRefreshTokenCookie = (cookieName = 'refreshToken'): void => {\n document.cookie = `${cookieName}=; expires=Thu, 01 Jan 1970 00:00:00 UTC; path=/;`;\n};\n\nexport const refreshAccessToken = async (config: AuthConfig): Promise<string> => {\n try {\n const refreshEndpoint = config.endpoints?.refresh || '/refresh';\n const response = await fetch(`${config.authUrl}${refreshEndpoint}`, {\n method: 'POST',\n credentials: 'include',\n });\n\n if (!response.ok) {\n if (response.status === 401 || response.status === 403) {\n clearRefreshTokenCookie(config.refreshTokenCookieName);\n throw new Error('Refresh token expired. Please log in again.');\n } else {\n throw new Error(`Failed to refresh token: ${response.status}`);\n }\n }\n\n const data: RefreshTokenResponse = await response.json();\n\n return data.accessToken;\n } catch (error) {\n clearRefreshTokenCookie(config.refreshTokenCookieName);\n throw error;\n }\n};\n\nexport const withTokenRefresh = async <T>(\n requestFn: () => Promise<T>,\n onTokenRefresh: (newToken: string) => void,\n onTokenClear: () => void,\n config: AuthConfig\n): Promise<T> => {\n try {\n return await requestFn();\n } catch (error) {\n if (error instanceof Error && error.message.includes('401')) {\n try {\n const newAccessToken = await tryRefreshToken(config);\n\n if (newAccessToken) {\n onTokenRefresh(newAccessToken);\n\n return await requestFn();\n } else {\n onTokenClear();\n clearRefreshTokenCookie(config.refreshTokenCookieName);\n throw new Error('No valid refresh token available');\n }\n } catch (refreshError) {\n onTokenClear();\n clearRefreshTokenCookie(config.refreshTokenCookieName);\n throw refreshError;\n }\n }\n\n throw error;\n }\n};\n\nexport const getStorageItem = (\n key: string,\n storageType: 'localStorage' | 'sessionStorage' = 'localStorage'\n): string | null => {\n if (typeof window === 'undefined') return null;\n\n const storage = storageType === 'localStorage' ? window.localStorage : window.sessionStorage;\n\n return storage.getItem(key);\n};\n\nexport const setStorageItem = (\n key: string,\n value: string,\n storageType: 'localStorage' | 'sessionStorage' = 'localStorage'\n): void => {\n if (typeof window === 'undefined') return;\n\n const storage = storageType === 'localStorage' ? window.localStorage : window.sessionStorage;\n\n storage.setItem(key, value);\n};\n\nexport const removeStorageItem = (\n key: string,\n storageType: 'localStorage' | 'sessionStorage' = 'localStorage'\n): void => {\n if (typeof window === 'undefined') return;\n\n const storage = storageType === 'localStorage' ? window.localStorage : window.sessionStorage;\n\n storage.removeItem(key);\n};\n","import { createContext, type ReactNode, useContext } from 'react';\n\nimport type { AuthConfig } from '../types';\n\ninterface AuthConfigContextType {\n config: AuthConfig;\n}\n\nconst AuthConfigContext = createContext<AuthConfigContextType | undefined>(undefined);\n\ninterface AuthConfigProviderProps {\n children: ReactNode;\n config: AuthConfig;\n}\n\nexport const AuthConfigProvider = ({ children, config }: AuthConfigProviderProps) => {\n const configWithDefaults: AuthConfig = {\n storageType: 'localStorage',\n accessTokenKey: 'accessToken',\n refreshTokenCookieName: 'refreshToken',\n endpoints: {\n refresh: '/refresh',\n logout: '/logout',\n ...config.endpoints,\n },\n ...config,\n };\n\n return <AuthConfigContext.Provider value={{ config: configWithDefaults }}>{children}</AuthConfigContext.Provider>;\n};\n\nexport const useAuthConfig = (): AuthConfig => {\n const context = useContext(AuthConfigContext);\n\n if (!context) {\n throw new Error('useAuthConfig must be used within an AuthConfigProvider');\n }\n\n return context.config;\n};\n","import { createContext, type ReactNode, useCallback, useContext, useState } from 'react';\n\nimport type { UserContextType, UserInfo } from '../types';\nimport { extractUserFromToken } from '../utils';\n\nconst UserContext = createContext<UserContextType | undefined>(undefined);\n\nexport const UserProvider = ({ children }: { children: ReactNode }) => {\n const [user, setUser] = useState<UserInfo | null>(null);\n\n const updateUserFromToken = useCallback((token: string) => {\n const userInfo = extractUserFromToken(token);\n\n if (userInfo) {\n setUser(userInfo);\n } else {\n console.warn('Could not extract user information from token');\n setUser(null);\n }\n }, []);\n\n const clearUser = useCallback(() => {\n setUser(null);\n }, []);\n\n return (\n <UserContext.Provider value={{ user, setUser, updateUserFromToken, clearUser }}>\n {children}\n </UserContext.Provider>\n );\n};\n\nexport const useUser = (): UserContextType => {\n const context = useContext(UserContext);\n\n if (!context) {\n throw new Error('useUser must be used within a UserProvider');\n }\n\n return context;\n};\n","import { useEffect } from 'react';\nimport { useLocation, useNavigate } from 'react-router-dom';\n\nimport { useAuth } from '../contexts/AuthContext';\nimport type { UseAuthRedirectOptions } from '../types';\n\nexport const useAuthRedirect = (options: UseAuthRedirectOptions = {}) => {\n const { redirectTo = '/home', redirectFrom = '/', condition = 'authenticated' } = options;\n\n const navigate = useNavigate();\n const location = useLocation();\n const { isAuthenticated } = useAuth();\n\n useEffect(() => {\n const shouldRedirect =\n condition === 'authenticated'\n ? isAuthenticated && location.pathname === redirectFrom\n : !isAuthenticated && location.pathname !== redirectFrom;\n\n if (shouldRedirect) {\n navigate(redirectTo);\n }\n }, [isAuthenticated, navigate, location.pathname, redirectTo, redirectFrom, condition]);\n\n return { isAuthenticated };\n};\n\nexport const useRedirectIfAuthenticated = (to = '/home', from = '/') => {\n return useAuthRedirect({ redirectTo: to, redirectFrom: from, condition: 'authenticated' });\n};\n\nexport const useRedirectIfUnauthenticated = (to = '/login') => {\n return useAuthRedirect({ redirectTo: to, condition: 'unauthenticated' });\n};\n","import { useCallback, useEffect, useState } from 'react';\n\nimport { useAuthConfig } from '../contexts/AuthConfigContext';\nimport { useAuth } from '../contexts/AuthContext';\nimport { removeStorageItem, tryRefreshToken } from '../utils';\n\nexport const useTokenInitialization = () => {\n const { login, isAuthenticated } = useAuth();\n const config = useAuthConfig();\n const [isInitializing, setIsInitializing] = useState(true);\n\n const initializeToken = useCallback(async () => {\n try {\n const newAccessToken = await tryRefreshToken(config);\n\n if (newAccessToken) {\n login(newAccessToken);\n }\n } catch {\n removeStorageItem(config.accessTokenKey!, config.storageType);\n } finally {\n setIsInitializing(false);\n }\n }, [login, config]);\n\n useEffect(() => {\n if (!isAuthenticated) {\n initializeToken();\n } else {\n setIsInitializing(false);\n }\n }, [initializeToken, isAuthenticated]);\n\n return { isInitializing };\n};\n","import { useCallback, useRef } from 'react';\n\nimport { useAuthConfig } from '../contexts/AuthConfigContext';\nimport { useAuth } from '../contexts/AuthContext';\nimport type { RefreshTokenResponse } from '../types';\nimport { clearRefreshTokenCookie } from '../utils';\n\nexport const useTokenRefresh = () => {\n const { login, logout, accessToken } = useAuth();\n const config = useAuthConfig();\n const refreshPromiseRef = useRef<Promise<string> | null>(null);\n\n const hasRefreshToken = useCallback((): boolean => {\n if (typeof document === 'undefined') return false;\n\n return document.cookie\n .split(';')\n .some((cookie) => cookie.trim().startsWith(`${config.refreshTokenCookieName}=`));\n }, [config.refreshTokenCookieName]);\n\n const clearTokens = useCallback(() => {\n logout();\n refreshPromiseRef.current = null;\n clearRefreshTokenCookie(config.refreshTokenCookieName);\n }, [logout, config.refreshTokenCookieName]);\n\n const performTokenRefresh = useCallback(async (): Promise<string> => {\n try {\n const refreshEndpoint = config.endpoints?.refresh || '/refresh';\n const response = await fetch(`${config.authUrl}${refreshEndpoint}`, {\n method: 'POST',\n credentials: 'include',\n });\n\n if (!response.ok) {\n if (response.status === 401 || response.status === 403) {\n clearTokens();\n throw new Error('Refresh token expired. Please log in again.');\n } else {\n throw new Error(`Failed to refresh token: ${response.status}`);\n }\n }\n\n const data: RefreshTokenResponse = await response.json();\n\n login(data.accessToken);\n\n return data.accessToken;\n } catch (error) {\n clearTokens();\n throw error;\n }\n }, [login, clearTokens, config.authUrl, config.endpoints?.refresh]);\n\n const refreshTokens = useCallback(async (): Promise<string> => {\n if (refreshPromiseRef.current) {\n return refreshPromiseRef.current;\n }\n\n refreshPromiseRef.current = performTokenRefresh();\n\n try {\n const newAccessToken = await refreshPromiseRef.current;\n\n refreshPromiseRef.current = null;\n\n return newAccessToken;\n } catch (error) {\n refreshPromiseRef.current = null;\n throw error;\n }\n }, [performTokenRefresh]);\n\n const getValidAccessToken = useCallback(async (): Promise<string> => {\n if (!accessToken) {\n throw new Error('No access token available. Please log in.');\n }\n\n return accessToken;\n }, [accessToken]);\n\n return {\n refreshTokens,\n getValidAccessToken,\n hasRefreshToken,\n clearTokens,\n };\n};\n"],"mappings":"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","names":["createContext","useCallback","useContext","useState","createContext","useContext","jsx","createContext","useContext","jsx","createContext","useState","useCallback","useContext","jsx","useEffect","useLocation","useLocation","useEffect","useCallback","useEffect","useState","useState","useCallback","useEffect","useCallback","useCallback"]}
|
package/package.json
ADDED
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@imapps/web-utils",
|
|
3
|
+
"version": "0.5.1",
|
|
4
|
+
"description": "Shared web utilities for frontend apps",
|
|
5
|
+
"author": "igor-siergiej",
|
|
6
|
+
"license": "AGPL-3.0 license",
|
|
7
|
+
"publishConfig": {
|
|
8
|
+
"registry": "https://registry.npmjs.org/",
|
|
9
|
+
"access": "public"
|
|
10
|
+
},
|
|
11
|
+
"repository": {
|
|
12
|
+
"type": "git",
|
|
13
|
+
"url": "git+https://github.com/igor-siergiej/utils.git"
|
|
14
|
+
},
|
|
15
|
+
"main": "build/index.cjs",
|
|
16
|
+
"module": "build/index.js",
|
|
17
|
+
"types": "build/index.d.ts",
|
|
18
|
+
"exports": {
|
|
19
|
+
".": {
|
|
20
|
+
"types": "./build/index.d.ts",
|
|
21
|
+
"import": "./build/index.js",
|
|
22
|
+
"require": "./build/index.cjs"
|
|
23
|
+
}
|
|
24
|
+
},
|
|
25
|
+
"files": [
|
|
26
|
+
"build"
|
|
27
|
+
],
|
|
28
|
+
"scripts": {
|
|
29
|
+
"build": "tsup",
|
|
30
|
+
"clean": "rimraf build",
|
|
31
|
+
"prepack": "bun run clean && bun run build"
|
|
32
|
+
},
|
|
33
|
+
"sideEffects": false,
|
|
34
|
+
"peerDependencies": {
|
|
35
|
+
"react": ">=18.0.0",
|
|
36
|
+
"react-router-dom": ">=6.0.0"
|
|
37
|
+
},
|
|
38
|
+
"devDependencies": {
|
|
39
|
+
"@types/react": "^19.1.13",
|
|
40
|
+
"react": "^19.1.1",
|
|
41
|
+
"react-router-dom": "^7.9.1",
|
|
42
|
+
"rimraf": "^6.0.1",
|
|
43
|
+
"tsup": "^8.5.0",
|
|
44
|
+
"typescript": "^5.9.2"
|
|
45
|
+
}
|
|
46
|
+
}
|