@spidy092/auth-client 3.1.3 → 3.1.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/api.cjs +34 -0
- package/dist/api.cjs.map +1 -1
- package/dist/api.js +34 -0
- package/dist/api.js.map +1 -1
- package/dist/index.cjs +194 -31
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +194 -31
- package/dist/index.js.map +1 -1
- package/dist/preferences.cjs +34 -0
- package/dist/preferences.cjs.map +1 -1
- package/dist/preferences.js +34 -0
- package/dist/preferences.js.map +1 -1
- package/dist/react/AuthProvider.cjs +188 -31
- package/dist/react/AuthProvider.cjs.map +1 -1
- package/dist/react/AuthProvider.js +188 -31
- package/dist/react/AuthProvider.js.map +1 -1
- package/dist/react/PreferencesProvider.cjs +34 -0
- package/dist/react/PreferencesProvider.cjs.map +1 -1
- package/dist/react/PreferencesProvider.js +34 -0
- package/dist/react/PreferencesProvider.js.map +1 -1
- package/dist/react/useAuth.cjs.map +1 -1
- package/dist/react/useAuth.js.map +1 -1
- package/dist/react/useSessionMonitor.cjs +61 -1
- package/dist/react/useSessionMonitor.cjs.map +1 -1
- package/dist/react/useSessionMonitor.js +61 -1
- package/dist/react/useSessionMonitor.js.map +1 -1
- package/dist/utils/jwt.cjs.map +1 -1
- package/dist/utils/jwt.js.map +1 -1
- package/package.json +1 -1
|
@@ -38,8 +38,10 @@ var import_react = __toESM(require("react"), 1);
|
|
|
38
38
|
// token.js
|
|
39
39
|
var import_jwt_decode = require("jwt-decode");
|
|
40
40
|
var accessToken = null;
|
|
41
|
+
var idToken = null;
|
|
41
42
|
var listeners = /* @__PURE__ */ new Set();
|
|
42
43
|
var REFRESH_COOKIE = "account_refresh_token";
|
|
44
|
+
var ID_TOKEN_KEY = "auth_id_token";
|
|
43
45
|
var COOKIE_MAX_AGE = 7 * 24 * 60 * 60;
|
|
44
46
|
function secureAttribute() {
|
|
45
47
|
var _a;
|
|
@@ -108,12 +110,14 @@ function getToken() {
|
|
|
108
110
|
function clearToken() {
|
|
109
111
|
if (!accessToken) {
|
|
110
112
|
writeAccessToken(null);
|
|
113
|
+
clearIdToken();
|
|
111
114
|
clearRefreshToken();
|
|
112
115
|
return;
|
|
113
116
|
}
|
|
114
117
|
const previousToken = accessToken;
|
|
115
118
|
accessToken = null;
|
|
116
119
|
writeAccessToken(null);
|
|
120
|
+
clearIdToken();
|
|
117
121
|
clearRefreshToken();
|
|
118
122
|
listeners.forEach((listener) => {
|
|
119
123
|
try {
|
|
@@ -123,6 +127,22 @@ function clearToken() {
|
|
|
123
127
|
}
|
|
124
128
|
});
|
|
125
129
|
}
|
|
130
|
+
function getIdToken() {
|
|
131
|
+
if (idToken) return idToken;
|
|
132
|
+
try {
|
|
133
|
+
idToken = sessionStorage.getItem(ID_TOKEN_KEY) || null;
|
|
134
|
+
} catch {
|
|
135
|
+
idToken = null;
|
|
136
|
+
}
|
|
137
|
+
return idToken;
|
|
138
|
+
}
|
|
139
|
+
function clearIdToken() {
|
|
140
|
+
idToken = null;
|
|
141
|
+
try {
|
|
142
|
+
sessionStorage.removeItem(ID_TOKEN_KEY);
|
|
143
|
+
} catch {
|
|
144
|
+
}
|
|
145
|
+
}
|
|
126
146
|
var REFRESH_TOKEN_KEY = "auth_refresh_token";
|
|
127
147
|
var _persistRefreshToken = false;
|
|
128
148
|
function shouldUseLocalStorage() {
|
|
@@ -177,6 +197,15 @@ function clearRefreshToken() {
|
|
|
177
197
|
} catch (err) {
|
|
178
198
|
}
|
|
179
199
|
}
|
|
200
|
+
function addTokenListener(listener) {
|
|
201
|
+
if (typeof listener !== "function") {
|
|
202
|
+
throw new Error("Token listener must be a function");
|
|
203
|
+
}
|
|
204
|
+
listeners.add(listener);
|
|
205
|
+
return () => {
|
|
206
|
+
listeners.delete(listener);
|
|
207
|
+
};
|
|
208
|
+
}
|
|
180
209
|
if (typeof window !== "undefined" && window.addEventListener) {
|
|
181
210
|
window.addEventListener("storage", (event) => {
|
|
182
211
|
if (event.key !== "authToken") return;
|
|
@@ -290,6 +319,28 @@ function acquireLoginLock(clientKey, redirectUri, ttlMs = 5e3) {
|
|
|
290
319
|
}
|
|
291
320
|
return true;
|
|
292
321
|
}
|
|
322
|
+
async function reportClientDiagnostic(safe) {
|
|
323
|
+
if (typeof fetch !== "function" || typeof getToken !== "function") return;
|
|
324
|
+
if (safe.outcome === "SUCCESS" && !safe.event.startsWith("PROFILE_") && !safe.event.startsWith("SESSION_")) return;
|
|
325
|
+
const { authBaseUrl } = getConfig();
|
|
326
|
+
const token = getToken();
|
|
327
|
+
if (!authBaseUrl || !token) return;
|
|
328
|
+
try {
|
|
329
|
+
await fetch(`${authBaseUrl.replace(/\/+$/, "")}/client-telemetry`, {
|
|
330
|
+
method: "POST",
|
|
331
|
+
credentials: "include",
|
|
332
|
+
keepalive: true,
|
|
333
|
+
headers: {
|
|
334
|
+
"Content-Type": "application/json",
|
|
335
|
+
Authorization: `Bearer ${token}`,
|
|
336
|
+
"X-Correlation-ID": safe.correlationId,
|
|
337
|
+
"X-Request-ID": safe.correlationId
|
|
338
|
+
},
|
|
339
|
+
body: JSON.stringify(safe)
|
|
340
|
+
});
|
|
341
|
+
} catch {
|
|
342
|
+
}
|
|
343
|
+
}
|
|
293
344
|
async function emitAuthDiagnostic(event, outcome, reasonCode, details = {}) {
|
|
294
345
|
const context = getDiagnosticContext();
|
|
295
346
|
const safe = {
|
|
@@ -306,6 +357,7 @@ async function emitAuthDiagnostic(event, outcome, reasonCode, details = {}) {
|
|
|
306
357
|
};
|
|
307
358
|
const method = outcome === "FAILURE" ? "error" : outcome === "WARNING" ? "warn" : "info";
|
|
308
359
|
console[method]("[auth-client]", safe);
|
|
360
|
+
void reportClientDiagnostic(safe);
|
|
309
361
|
return safe;
|
|
310
362
|
}
|
|
311
363
|
|
|
@@ -368,6 +420,7 @@ async function logout(options = {}) {
|
|
|
368
420
|
const { clientKey, authBaseUrl, accountUiUrl } = getConfig();
|
|
369
421
|
const scope = options.scope === "client" ? "client" : "sso";
|
|
370
422
|
const token = getToken();
|
|
423
|
+
const idToken2 = getIdToken();
|
|
371
424
|
const refreshToken2 = getRefreshToken();
|
|
372
425
|
console.log("\u{1F6AA} Smart Logout initiated", {
|
|
373
426
|
mode: isRouterMode() ? "ROUTER" : "CLIENT",
|
|
@@ -376,6 +429,7 @@ async function logout(options = {}) {
|
|
|
376
429
|
});
|
|
377
430
|
emitAuthDiagnostic("LOGOUT_INITIATED", "PENDING", "NONE", { clientKey });
|
|
378
431
|
clearToken();
|
|
432
|
+
clearIdToken();
|
|
379
433
|
clearRefreshToken();
|
|
380
434
|
sessionStorage.removeItem("originalApp");
|
|
381
435
|
sessionStorage.removeItem("returnUrl");
|
|
@@ -388,7 +442,7 @@ async function logout(options = {}) {
|
|
|
388
442
|
"Authorization": token ? `Bearer ${token}` : "",
|
|
389
443
|
"Content-Type": "application/json"
|
|
390
444
|
},
|
|
391
|
-
body: JSON.stringify({ refreshToken: refreshToken2, scope })
|
|
445
|
+
body: JSON.stringify({ refreshToken: refreshToken2, idToken: idToken2, scope })
|
|
392
446
|
});
|
|
393
447
|
if (!response.ok) {
|
|
394
448
|
throw new Error(`Logout failed: ${response.status}`);
|
|
@@ -773,23 +827,72 @@ function stopSessionSecurity() {
|
|
|
773
827
|
|
|
774
828
|
// react/AuthProvider.jsx
|
|
775
829
|
var AuthContext = (0, import_react.createContext)();
|
|
776
|
-
function AuthProvider({ children, onSessionExpired }) {
|
|
830
|
+
function AuthProvider({ children, onSessionExpired, manageSessionSecurity = true }) {
|
|
777
831
|
const [token, setTokenState] = (0, import_react.useState)(getToken());
|
|
778
832
|
const [user, setUser] = (0, import_react.useState)(null);
|
|
779
833
|
const [loading, setLoading] = (0, import_react.useState)(!!token);
|
|
780
834
|
const [sessionValid, setSessionValid] = (0, import_react.useState)(true);
|
|
781
835
|
const sessionSecurityRef = (0, import_react.useRef)(null);
|
|
836
|
+
const onSessionExpiredRef = (0, import_react.useRef)(onSessionExpired);
|
|
837
|
+
const recoveryInFlightRef = (0, import_react.useRef)(null);
|
|
838
|
+
const profileRecoveryTokensRef = (0, import_react.useRef)(/* @__PURE__ */ new Set());
|
|
839
|
+
(0, import_react.useEffect)(() => {
|
|
840
|
+
onSessionExpiredRef.current = onSessionExpired;
|
|
841
|
+
}, [onSessionExpired]);
|
|
842
|
+
(0, import_react.useEffect)(() => {
|
|
843
|
+
const unsubscribe = addTokenListener((nextToken, previousToken) => {
|
|
844
|
+
if (nextToken === previousToken) return;
|
|
845
|
+
setTokenState(nextToken);
|
|
846
|
+
if (nextToken) {
|
|
847
|
+
setSessionValid(true);
|
|
848
|
+
setLoading(true);
|
|
849
|
+
} else {
|
|
850
|
+
setSessionValid(false);
|
|
851
|
+
setUser(null);
|
|
852
|
+
setLoading(false);
|
|
853
|
+
}
|
|
854
|
+
});
|
|
855
|
+
return unsubscribe;
|
|
856
|
+
}, []);
|
|
857
|
+
const invalidateLocalSession = () => {
|
|
858
|
+
clearToken();
|
|
859
|
+
setTokenState(null);
|
|
860
|
+
setUser(null);
|
|
861
|
+
setSessionValid(false);
|
|
862
|
+
setLoading(false);
|
|
863
|
+
};
|
|
782
864
|
const handleSessionInvalid = (reason) => {
|
|
783
865
|
console.log("\u{1F6A8} AuthProvider: Session invalidated -", reason);
|
|
784
|
-
|
|
785
|
-
|
|
786
|
-
|
|
787
|
-
|
|
788
|
-
|
|
789
|
-
|
|
866
|
+
if (recoveryInFlightRef.current) return recoveryInFlightRef.current;
|
|
867
|
+
const recover = async () => {
|
|
868
|
+
const callback = onSessionExpiredRef.current;
|
|
869
|
+
if (typeof callback === "function") {
|
|
870
|
+
try {
|
|
871
|
+
await callback(reason);
|
|
872
|
+
const recoveredToken = getToken();
|
|
873
|
+
if (recoveredToken) {
|
|
874
|
+
setTokenState(recoveredToken);
|
|
875
|
+
setSessionValid(true);
|
|
876
|
+
setLoading(true);
|
|
877
|
+
return true;
|
|
878
|
+
}
|
|
879
|
+
} catch (error) {
|
|
880
|
+
await emitAuthDiagnostic("SESSION_RECOVERY_FAILED", "FAILURE", reason, {
|
|
881
|
+
status: (error == null ? void 0 : error.status) || null,
|
|
882
|
+
errorCode: (error == null ? void 0 : error.code) || null
|
|
883
|
+
});
|
|
884
|
+
}
|
|
885
|
+
}
|
|
886
|
+
invalidateLocalSession();
|
|
887
|
+
return false;
|
|
888
|
+
};
|
|
889
|
+
recoveryInFlightRef.current = recover().finally(() => {
|
|
890
|
+
recoveryInFlightRef.current = null;
|
|
891
|
+
});
|
|
892
|
+
return recoveryInFlightRef.current;
|
|
790
893
|
};
|
|
791
894
|
(0, import_react.useEffect)(() => {
|
|
792
|
-
if (token && !sessionSecurityRef.current) {
|
|
895
|
+
if (manageSessionSecurity && token && !sessionSecurityRef.current) {
|
|
793
896
|
console.log("\u{1F510} AuthProvider: Starting session security");
|
|
794
897
|
const unsubscribe = onSessionInvalid(handleSessionInvalid);
|
|
795
898
|
sessionSecurityRef.current = startSessionSecurity(handleSessionInvalid);
|
|
@@ -801,11 +904,11 @@ function AuthProvider({ children, onSessionExpired }) {
|
|
|
801
904
|
}
|
|
802
905
|
};
|
|
803
906
|
}
|
|
804
|
-
if (!token && sessionSecurityRef.current) {
|
|
907
|
+
if ((!manageSessionSecurity || !token) && sessionSecurityRef.current) {
|
|
805
908
|
sessionSecurityRef.current.stopAll();
|
|
806
909
|
sessionSecurityRef.current = null;
|
|
807
910
|
}
|
|
808
|
-
}, [token]);
|
|
911
|
+
}, [manageSessionSecurity, token]);
|
|
809
912
|
(0, import_react.useEffect)(() => {
|
|
810
913
|
console.log("\u{1F50D} AuthProvider useEffect triggered:", {
|
|
811
914
|
hasToken: !!token,
|
|
@@ -826,26 +929,79 @@ function AuthProvider({ children, onSessionExpired }) {
|
|
|
826
929
|
authBaseUrl,
|
|
827
930
|
tokenPreview: token.slice(0, 50) + "..."
|
|
828
931
|
});
|
|
829
|
-
|
|
830
|
-
|
|
831
|
-
|
|
832
|
-
|
|
833
|
-
|
|
834
|
-
|
|
835
|
-
|
|
836
|
-
|
|
837
|
-
|
|
838
|
-
|
|
839
|
-
|
|
840
|
-
|
|
841
|
-
|
|
842
|
-
}
|
|
843
|
-
|
|
844
|
-
|
|
845
|
-
|
|
846
|
-
|
|
847
|
-
|
|
848
|
-
|
|
932
|
+
let cancelled = false;
|
|
933
|
+
const fetchProfile = async (accessToken2) => {
|
|
934
|
+
const response = await fetch(`${authBaseUrl}/account/profile`, {
|
|
935
|
+
headers: { Authorization: `Bearer ${accessToken2}` },
|
|
936
|
+
credentials: "include"
|
|
937
|
+
});
|
|
938
|
+
console.log("\u{1F4E5} Profile response status:", response.status);
|
|
939
|
+
if (!response.ok) {
|
|
940
|
+
const error = new Error(`Profile request failed: ${response.status}`);
|
|
941
|
+
error.status = response.status;
|
|
942
|
+
throw error;
|
|
943
|
+
}
|
|
944
|
+
return response.json();
|
|
945
|
+
};
|
|
946
|
+
const loadProfile = async () => {
|
|
947
|
+
try {
|
|
948
|
+
const responseBody = await fetchProfile(token);
|
|
949
|
+
if (cancelled) return;
|
|
950
|
+
const userData = (responseBody == null ? void 0 : responseBody.data) ?? responseBody;
|
|
951
|
+
console.log("\u2705 Profile fetched successfully:", userData.email);
|
|
952
|
+
setUser(userData);
|
|
953
|
+
setSessionValid(true);
|
|
954
|
+
setLoading(false);
|
|
955
|
+
} catch (error) {
|
|
956
|
+
if (cancelled) return;
|
|
957
|
+
const status = Number((error == null ? void 0 : error.status) || 0);
|
|
958
|
+
const isUnauthorized = status === 401;
|
|
959
|
+
const callback = onSessionExpiredRef.current;
|
|
960
|
+
await emitAuthDiagnostic(
|
|
961
|
+
"PROFILE_REQUEST_FAILED",
|
|
962
|
+
isUnauthorized ? "FAILURE" : "WARNING",
|
|
963
|
+
isUnauthorized ? "PROFILE_UNAUTHORIZED" : status ? `PROFILE_HTTP_${status}` : "PROFILE_NETWORK_ERROR",
|
|
964
|
+
{ status, errorName: error == null ? void 0 : error.name, errorCode: error == null ? void 0 : error.code }
|
|
965
|
+
);
|
|
966
|
+
if (!isUnauthorized) {
|
|
967
|
+
console.warn("\u26A0\uFE0F Profile unavailable; retaining the current auth session", error);
|
|
968
|
+
setLoading(false);
|
|
969
|
+
return;
|
|
970
|
+
}
|
|
971
|
+
if (typeof callback === "function" && !profileRecoveryTokensRef.current.has(token)) {
|
|
972
|
+
profileRecoveryTokensRef.current.add(token);
|
|
973
|
+
try {
|
|
974
|
+
await callback("profile_unauthorized");
|
|
975
|
+
const recoveredToken = getToken();
|
|
976
|
+
if (recoveredToken && recoveredToken !== token) {
|
|
977
|
+
setTokenState(recoveredToken);
|
|
978
|
+
setSessionValid(true);
|
|
979
|
+
setLoading(true);
|
|
980
|
+
return;
|
|
981
|
+
}
|
|
982
|
+
if (recoveredToken) {
|
|
983
|
+
const responseBody = await fetchProfile(recoveredToken);
|
|
984
|
+
if (cancelled) return;
|
|
985
|
+
const userData = (responseBody == null ? void 0 : responseBody.data) ?? responseBody;
|
|
986
|
+
setUser(userData);
|
|
987
|
+
setSessionValid(true);
|
|
988
|
+
setLoading(false);
|
|
989
|
+
return;
|
|
990
|
+
}
|
|
991
|
+
} catch (recoveryError) {
|
|
992
|
+
await emitAuthDiagnostic("PROFILE_RECOVERY_FAILED", "FAILURE", "PROFILE_REFRESH_FAILED", {
|
|
993
|
+
status: (recoveryError == null ? void 0 : recoveryError.status) || null,
|
|
994
|
+
errorCode: (recoveryError == null ? void 0 : recoveryError.code) || null
|
|
995
|
+
});
|
|
996
|
+
}
|
|
997
|
+
}
|
|
998
|
+
invalidateLocalSession();
|
|
999
|
+
}
|
|
1000
|
+
};
|
|
1001
|
+
void loadProfile();
|
|
1002
|
+
return () => {
|
|
1003
|
+
cancelled = true;
|
|
1004
|
+
};
|
|
849
1005
|
}, [token]);
|
|
850
1006
|
const login2 = (clientKey, redirectUri, state) => {
|
|
851
1007
|
login(clientKey, redirectUri, state);
|
|
@@ -874,6 +1030,7 @@ function AuthProvider({ children, onSessionExpired }) {
|
|
|
874
1030
|
setToken(newToken);
|
|
875
1031
|
setTokenState(newToken);
|
|
876
1032
|
setSessionValid(true);
|
|
1033
|
+
if (newToken) setLoading(true);
|
|
877
1034
|
},
|
|
878
1035
|
clearToken: () => {
|
|
879
1036
|
stopSessionSecurity();
|